MySql - Get field from table 2, If not then from table 1 - mysql

I have two table complain and repair. I want to get ass_to_per [Latest one] from repair or from complain if the id of complain is not present in repair.
Explanation:
I want to get the ass_to_per from the complain table, and also from the repair table. But there is a relation between them, in repair there is a field called com_id which is a foreign key. So i want to get the ass_to_per from complain and also check the repair for the foreign key, if any then check the ass_to_per of repair. If any then get it as result.
I have sqlfiddle, For online testing: sqlfiddle.com
The table and data given below.
Complain
CREATE TABLE `complain` (
`id` int(11) NOT NULL,
`ass_to_per` varchar(50) NOT NULL
);
INSERT INTO `complain` (`id`, `ass_to_per`) VALUES
(1, 'frayne'),
(2, 'murad'),
(4, 'frayne'),
(5, 'murad'),
(6, 'frayne'),
(7, 'frayne');
Repair
CREATE TABLE `repair` (
`id` int(11) NOT NULL,
`com_id` int(11) NOT NULL,
`ass_to_per` varchar(50) NOT NULL
);
INSERT INTO `repair` (`id`, `com_id`, `ass_to_per`) VALUES
(1, 1, 'frayne'),
(2, 1, 'murad'),
(3, 4, 'frayne'),
(4, 6, 'murad'),
(5, 2, 'murad'),
(6, 5, 'frayne');
My Query:
SELECT * FROM `complain`
WHERE `id` IN (SELECT DISTINCT(`com_id`) FROM `repair` WHERE `ass_to_per` = 'frayne') OR `ass_to_per`='frayne'
Query Result
id | ass_to_per
--------------
1 | frayne
4 | frayne
5 | murad
6 | frayne
7 | frayne
Analysis
id | ass_to_per[complain] | ass_to_per[repair]
--------------
1 | murad | frayne
2 | murad | murad
4 | frayne | frayne //need this one
5 | murad | frayne //need this one
6 | frayne | murad
7 | frayne | //need this one
Expected result:
id | ass_to_per
--------------
4 | frayne //ass_to_per from repair
5 | frayne //ass_to_per from repair
7 | frayne //ass_to_per from complain

COALESCE() will output the first non-null parameter it finds, so using a join you can probably get ass_to_per from complain or repair depending on which one exists:
SELECT
complain.id,
COALESCE(repair3.ass_to_per, complain.ass_to_per) as ass_to_per
FROM complain
LEFT JOIN
(SELECT max(id) as maxid, com_id FROM repair GROUP BY com_id) as repair2
ON complain.id = repair2.com_id
LEFT JOIN repair as repair3
ON repair2.maxid = repair3.id
GROUP BY complain.id
If you want to further filter (like in your example on 'frayne') on computed ass_to_per, just embed this select as a subquery:
SELECT *
FROM (
SELECT
complain.id,
COALESCE(repair3.ass_to_per, complain.ass_to_per) as ass_to_per
FROM complain
LEFT JOIN (SELECT max(id) as maxid, com_id FROM repair GROUP BY com_id) AS repair2
ON complain.id = repair2.com_id
LEFT JOIN repair as repair3
ON repair2.maxid = repair3.id
GROUP BY complain.id
) AS mydata
WHERE mydata.ass_to_per = 'frayne'
ORDER BY mydata.id;
Fiddle here : http://sqlfiddle.com/#!9/33433/49

SELECT c.id
FROM complain c
LEFT
JOIN
( SELECT x.*
FROM repair x
JOIN
( SELECT com_id,MAX(id) id FROM repair GROUP BY com_id ) y
ON y.com_id = x.com_id
AND y.id = x.id
) r
ON r.com_id = c.id
WHERE COALESCE(r.ass_to_per,c.ass_to_per) = 'frayne';

Related

How do I select the max(timestamp) from a relational mysql table fast

We are developing a ticket system and for the dashboard we want to show the tickets with it's latest status. We have two tables. The first one for the ticket itself and a second table for the individual edits.
The system is running already, but the performance for the dashboard is very bad (6 seconds for ~1300 tickets). At first we used a statemant which selected 'where timestamp = (select max(Timestamp))' for every ticket. In the second step we created a view which only includes the latest timestamp for every ticket, but we are not able to also include the correct status into this view.
So the main Problem might be, that we can't build a table in which for every ticket the lastest ins_date and also the latest status is selected.
Simplyfied database looks like:
CREATE TABLE `ticket` (
`id` int(10) NOT NULL,
`betreff` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ticket_relation` (
`id` int(11) NOT NULL,
`ticket` int(10) NOT NULL,
`info` varchar(10000) DEFAULT NULL,
`status` int(1) NOT NULL DEFAULT '0',
`ins_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`ins_user` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `ticket` (`id`, `betreff`) VALUES
(1, 'Technische Frage'),
(2, 'Ticket 2'),
(3, 'Weitere Fragen');
INSERT INTO `ticket_relation` (`id`, `ticket`, `info`, `status`, `ins_date`, `ins_user`) VALUES
(1, 1, 'Betreff 1', 0, '2019-05-28 11:02:18', 123),
(2, 1, 'Betreff 2', 3, '2019-05-28 12:07:36', 123),
(3, 2, 'Betreff 3', 0, '2019-05-29 06:49:32', 123),
(4, 3, 'Betreff 4', 1, '2019-05-29 07:44:07', 123),
(5, 2, 'Betreff 5', 1, '2019-05-29 07:49:32', 123),
(6, 2, 'Betreff 6', 3, '2019-05-29 08:49:32', 123),
(7, 3, 'Betreff 7', 2, '2019-05-29 09:49:32', 123),
(8, 2, 'Betreff 8', 1, '2019-05-29 10:49:32', 123),
(9, 3, 'Betreff 9', 2, '2019-05-29 11:49:32', 123),
(10, 3, 'Betreff 10', 3, '2019-05-29 12:49:32', 123);
I have created a SQL Fiddle: http://sqlfiddle.com/#!9/a873b6/3
The first three Statements are attempts that won't work correct or way too slow. The last one is the key I think, but I don't understand, why this gets the status wrong.
The attempt to create the table with latest ins_date AND status for each ticket:
SELECT
ticket, status, MAX(ins_date) as max_date
FROM
ticket_relation
GROUP BY
ticket
ORDER BY
ins_date DESC;
This query gets the correct (latest) ins_date for every ticket, but not the latest status:
+--------+--------+----------------------+
| ticket | status | max_date |
+--------+--------+----------------------+
| 3 | 1 | 2019-05-29T12:49:32Z |
+--------+--------+----------------------+
| 2 | 0 | 2019-05-29T10:49:32Z |
+--------+--------+----------------------+
| 1 | 0 | 2019-05-28T12:07:36Z |
+--------+--------+----------------------+
Expected output would be this:
+--------+--------+----------------------+
| ticket | status | max_date |
+--------+--------+----------------------+
| 3 | 3 | 2019-05-29T12:49:32Z |
+--------+--------+----------------------+
| 2 | 1 | 2019-05-29T10:49:32Z |
+--------+--------+----------------------+
| 1 | 3 | 2019-05-28T12:07:36Z |
+--------+--------+----------------------+
Is there a efficient way to select the latest timestamp and status for every ticket in the tiket-table?
Other approach is to think filtering not GROUPing..
Query
SELECT
ticket_relation_1.ticket
, ticket_relation_1.status
, ticket_relation_1.ins_date
FROM
ticket_relation AS ticket_relation_1
LEFT JOIN
ticket_relation AS ticket_relation_2
ON
ticket_relation_1.ticket = ticket_relation_2.ticket
AND
ticket_relation_1.ins_date < ticket_relation_2.ins_date
WHERE
ticket_relation_2.id IS NULL
ORDER BY
ticket_relation_1.id DESC
Result
| ticket | status | ins_date |
| ------ | ------ | ------------------- |
| 3 | 3 | 2019-05-29 12:49:32 |
| 2 | 1 | 2019-05-29 10:49:32 |
| 1 | 3 | 2019-05-28 12:07:36 |
see demo
This query would require a index KEY(ticket, ins_date, id) to get max performance..
One solution would be to use a subquery to compute the latest insert date for each ticket, and then to join the results with the original table, like:
SELECT t.ticket, t.status, t.ins_date
FROM ticket_relation t
INNER JOIN (
SELECT ticket, max(ins_date) max_ins_date
FROM ticket_relation
GROUP BY ticket
) x ON t.ticket = x.ticket AND t.ins_date = x.max_ins_date
For better performance with this query, you want an index on (ticket, ins_date).
Anoter option would be to use a NOT EXISTS condition to ensure that only the latest record is selected, like:
SELECT t.ticket, t.status, t.ins_date
FROM ticket_relation t
WHERE NOT EXISTS (
SELECT 1
FROM ticket_relation t1
WHERE t1.ticket = t.ticket AND t1.ins_date > t.ins_date)
)
NB: when dealing with GROUP BY, all non-aggregated columns must appear in the GROUP BY clause. Else, you will get either an error or unprectictable results (depending on whether server option ONLY_FULL_GROUP_BY is, respectively, enabled or disabled).
If you are able to upgrade to a recent version of mysql (8.0), then window functions can be used to simplify the query and possibly increase its performance, like:
SELECT ticket, status, ins_date
FROM (
SELECT
ticket,
status,
ins_date,
row_number() over(partition by ticket order by ins_date desc) rn
FROM ticket_relation
) x WHERE rn = 1
You can try below query -
SELECT
ticket, status, ins_date as max_date
FROM ticket_relation a
where ins_date in (select max(ins_date) from ticket_relation b where a.ticket=b.ticket)

LIMIT number of rows in a JOIN between MySQL tables

What I have
I have the following two tables in a MySQL database (version 5.6.35).
CREATE TABLE `Runs` (
`Name` varchar(200) NOT NULL,
`Run` varchar(200) NOT NULL,
`Points` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Runs` (`Name`, `Run`, `Points`) VALUES
('John', 'A08', 12),
('John', 'A09', 3),
('John', 'A01', 15),
('Kate', 'A02', 92),
('Kate', 'A03', 1),
('Kate', 'A04', 33),
('Peter', 'A05', 8),
('Peter', 'A06', 14),
('Peter', 'A07', 5);
CREATE TABLE `Users` (
`Name` varchar(500) NOT NULL,
`NumberOfRun` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Users` (`Name`, `NumberOfRun`) VALUES
('John', 2),
('Kate', 1),
('Peter', 3);
ALTER TABLE `Runs`
ADD PRIMARY KEY (`Run`);
What is my target
John have Users.NumberOfRun=2, so I will extract the 2 top records from Runs table
Kate have Users.NumberOfRun=1, so I will extract the 1 top record from Runs table
Peter have Users.NumberOfRun=3, so I will extract the 3 top records from Runs table
I would like to came to the following result
+-------+-----+--------+
| Name | Run | Points |
+-------+-----+--------+
| John | A01 | 15 |
| John | A08 | 12 |
| Kate | A02 | 92 |
| Peter | A06 | 14 |
| Peter | A05 | 8 |
| Peter | A07 | 5 |
+-------+-----+--------+
What I have tried
First of all, if it was SQL Server I would use ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ) AS [rn] function to the Runs table and then make a JOIN with the Users table on Users.NumberOfRun<=[rn].
I have read this document but it seems that PARTITONING in MySQL it is available since version 8.X, but I am using the 5.6.X version.
Finally, I have tried this query, based on this Stackoverflow answer:
SELECT t0.Name,t0.Run
FROM Runs AS t0
LEFT JOIN Runs AS t1 ON t0.Name=t1.Name AND t0.Run=t1.Run AND t1.Points>t0.Points
WHERE t1.Points IS NULL;
but it doesn't give me the row number, which is essentially for me to make a JOIN as described above.
SQL Fiddle to this example.
A combination of 'group_concat' and 'find_in_set', followed by the filtering using the position returned by 'find_in_set' will do the job for you.
GROUP_CONCAT will sort the data in descending order of points first.
GROUP_CONCAT(Run ORDER BY Points DESC)
FIND_IN_SET will then retrieve the number of rows you want to include in the result.
FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
The below query should work for you.
SELECT
Runs.*
FROM
Runs
INNER JOIN (
SELECT
Name, GROUP_CONCAT(Run ORDER BY Points DESC) grouped_run
FROM
Runs
GROUP BY Name
) group_max ON Runs.Name = group_max.Name
INNER JOIN Users ON Users.Name = Runs.Name
WHERE FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
ORDER BY
Runs.Name Asc, Runs.Points DESC;

Custom query with group by and then count

I am using events.I would like to know how to calculate sum in event or using single query
http://sqlfiddle.com/#!9/ad6d1c/1
DDL for question:
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`group_id` int(11) NOT NULL DEFAULT '0',
`in_use` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0->in_use,1->not_in_use',
`auto_assign` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0->Yes,1->No'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `table1`
ADD PRIMARY KEY (`id`);
ALTER TABLE `table1`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
INSERT INTO `table1` (`id`, `group_id`, `in_use`, `auto_assign`) VALUES
(1, 3, 1, 0),(2, 2, 0,1),(3, 1, 1, 1),(4, 3, 1, 0),(5, 3, 0, 0),(6, 3, 0, 1),
(7, 3, 1, 0),(8, 3, 0, 1),(9, 3, 0, 1),(10, 3, 0, 1),(11, 3, 0, 1),(12, 3, 1, 1),
(13, 3, 1, 0),(14, 3, 0, 0),(15, 3, 0, 0),(16, 3, 0, 0),(17, 3, 0, 0),(18, 3, 1, 1),
(19, 3, 0, 0),(20, 3, 0, 0)
Expected Output :
| count | in_use | auto_assign | sum | check_count |
|-------|--------|-------------|------|------------ |
| 7 | 0 | 0 | 11 | 5 |
| 5 | 0 | 1 | 07 | 3 |
| 4 | 1 | 0 | 11 | 5 |
| 2 | 1 | 1 | 07 | 3 |
Here we can see that auto_assign=0 have total 11 count(7+4) and
auto_assign=1 have 7 count(5+2) this count should be stored into new column sum.
check_count column is percentage value of sum column.Percentage will be predefined.
Lets take 50%, So count 11(sum column value) ->50% = 5.5 = ROUND(5.5) == 5(In integer). Same way count 7(sum column value)->50% = 3.5 =ROUND(3.5)=3(Integer)
Here 5 > 4(auto_assign=0 and in_use=1 ).So have to insert record into another table(table2). if not then not.
Same way, If 3 >2 then also need to insert record into another table(table2).if not then not.
Note : This logic I would like to implement in event
This is bit complicated, but please suggest me how to do this in event.
Detail clarification :
here percentage_Value is 5 for auto_assign =0.But auto_assign=0 and in_use=1 have count is 4 which less than 5 ,then have to insert record into table 2.
suppose,if we get count is 6 for auto_assign=0 and in_use=1 ,Then no need to insert record into table2.
Same way,
here percentage_Value is 3 for auto_assign =1.But auto_assign=1 and in_use=1 have count is 2 which less than 3 ,then have to insert record into table 2.
suppose,if we get count is 4 for auto_assign=1 and in_use=1 ,Then no need to insert record into table2.
Insert query into table2:
Insert into table2(cli_group_id,auto_assign,percentage_value,result_value) values(3,0,5,4)
DEMO Fiddle
Break the problem down: we need a count of the records by auto_Assigns; so we generate a derived table (B) with that value and join back to your base table on auto_Assign. This then gives us the column we need for some and we use the truncate function and a division model to get the check_count
SELECT count(*), in_use, A.Auto_Assign, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (Select Auto_Assign, count(*) sumC
from table1
where Group_ID = 3
Group by Auto_Assign) B
on A.Auto_Assign = B.Auto_Assign
WHERE GROUP_ID = 3
Group by in_use, A.Auto_Assign
we can eliminate the double where clause by joining on it:
SELECT count(*), in_use, A.Auto_Assign, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (Select Auto_Assign, count(*) sumC, Group_ID
from table1
where Group_ID = 3
Group by Auto_Assign, Group_ID) B
on A.Auto_Assign = B.Auto_Assign
and A.Group_ID = B.Group_ID
Group by in_use, A.Auto_Assign
I'd need clarification on the rest of the question: I'm not sure what 5 > 4 your'e looking at and I see no 3 other than the check count but that's not "the same way" so I'm not sure what you're after.
Here 5 > 4(auto_assign=0 and in_use=1 ).So have to insert record into another table(table2). if not then not.
Same way, If 3 >2 then also need to insert record into another table(table2).if not then not.
Note : This logic I would like to implement in event
This is bit complicated, but please suggest me how to do this in event.
So to create the event: DOCS
Which results in:
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 6 Minutes
DO
INSERT INTO table2
SELECT count(*) as mCount
, in_use
, A.Auto_Assign
, B.SumC, truncate(B.SumC/2,0) as check_Count
FROM table1 A
INNER JOIN (SELECT Auto_Assign, count(*) sumC, Group_ID
FROM table1
WHERE Group_ID = 3
GROUP BY Auto_Assign, Group_ID) B
ON A.Auto_Assign = B.Auto_Assign
AND A.Group_ID = B.Group_ID
GROUP BY in_use, A.Auto_Assign

Get rolled up sub total and total by joining multiple tables

Extending Rolling up addition using mysql
I can get rolling sum of rows https://stackoverflow.com/users/1529673/strawberry's answer for basic stuff so i tried to extend query by joining multiple tables but 1_keyworddefs.name='K2' is not affected. Getting same answer for 1_keyworddefs.name='K1' and K2.
Working query but directly by specifying 1_bugs.bug_id='2':
SELECT x.*, x.cf1 + x.cf2 sub_total, sum(y.cf1 + y.cf2) total FROM 1_bugs x INNER JOIN 1_bugs y ON y.bug_id <= x.bug_id INNER JOIN 1_keywords ON 1_keywords.bug_id = y.bug_id WHERE (x.bug_date BETWEEN '2016-07-19' AND '2016-07-22') AND (x.bug_id='2') AND (y.bug_status = 'VERIFIED' OR y.bug_status = 'CLOSED') AND (1_keywords.bug_id = x.bug_id) GROUP BY x.bug_id
Exact output (but i want to join table where 1_keywords.bug_id=1_bugs.bug_id matches instead of directly specifying 1_bugs.bug_id='2'):
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
Non-working query by joining tables (expecting answer like above):
SELECT x.*, x.cf1 + x.cf2 sub_total, sum(y.cf1 + y.cf2) total FROM 1_bugs x INNER JOIN 1_bugs y ON y.bug_id <= x.bug_id LEFT JOIN 1_keywords ON 1_keywords.bug_id = y.bug_id LEFT JOIN 1_keyworddefs ON 1_keyworddefs.id=1_keywords.keywordid AND 1_keyworddefs.name='K2' and 1_keywords.bug_id = y.bug_id WHERE (x.bug_date BETWEEN '2016-07-19' AND '2016-07-22') AND (y.bug_status = 'CLOSED' OR y.bug_status = 'VERIFIED') GROUP BY x.bug_id;
Expected:
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
Actual:
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
3 2016-07-22 2 2 CLOSED 4 7
** Here bug_id -> 3 row comes wrongly because 1_bugs.bug.id=1_keywords.bug_id doesn't match and there is no 1_keywords.bug_id='3' present in 1_keywords table.
DDLs:
-- 1_bugs table1 (master table) :
CREATE TABLE `1_bugs` (`bug_id` int(11) NOT NULL, `bug_date` date NOT NULL, `cf1` int(11) NOT NULL, `cf2` int(11) NOT NULL, `bug_status` varchar(200) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_bugs` (`bug_id`, `bug_date`, `cf1`, `cf2`, `bug_status`) VALUES (1, '2016-07-19', 3, 2, 'RESOLVED'), (2, '2016-07-19', 2, 1, VERIFIED'), (3, '2016-07-22', 2, 2, 'CLOSED');
-- 1_keywords table2 (having keyword ids):
CREATE TABLE `1_keywords` (`bug_id` int(11) NOT NULL, `keywordid` varchar(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_keywords` (`bug_id`, `keywordid`) VALUES (1, 'K1'), (2, 'K2');
-- 1_keyworddefs table3 (having keyword names according to keywordid):
CREATE TABLE `1_keyworddefs` (`id` int(11) NOT NULL, `name` varchar(200) NOT NULL, `description` varchar(200) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_keyworddefs` (`id`, `name`, `description`) VALUES (1, 'K1', 'My K1 item'), (2, 'K2', 'My K2 item');
Can someone please point me what i'm doing wrong?
Obviously things where not clear... after long discussions turns out what you wanted was to extract from bugzilla database a list of bugs for specific keyword grouped by date and a sum of cf1 + cf2 and the same sum of only 'opened' and 'verified' bugs.
Here we go
SELECT
b.lastdiffed,
d.name,
d.description,
SUM(IF(b.bug_status IN('CLOSED', 'VERIFIED'), b.cf1 + b.cf2, 0)) AS sub_total,
SUM(b.cf1 + b.cf2) AS running
FROM
bugs AS b
JOIN keywords AS k
ON ( k.bug_id = b.bug_id )
JOIN keyworddefs AS d
ON ( d.id = k.keywordid )
WHERE
1
AND d.name = 'SONY'
GROUP BY (b.lastdiffed)
ORDER BY b.lastdiffed ASC
Giving this result
+------------+------+-------------+-----------+---------+
| lastdiffed | name | description | sub_total | running |
+------------+------+-------------+-----------+---------+
| 2016-05-20 | SONY | sony items | 7 | 7 |
| 2016-06-20 | SONY | sony items | 11 | 17 |
| 2016-06-27 | SONY | sony items | 5 | 5 |
| 2016-06-29 | SONY | sony items | 5 | 5 |
+------------+------+-------------+-----------+---------+
Hope this helps.

JOIN query in MySQL produces wrong result

I have two tables complaints and complaints_reply in my MySQl database. Users can add complaints which are stored in complaints the complaints reply are stored in complaints_reply table. I am trying to JOIN both these table contents on a specific condition. Before I mention what I am trying to get and the problem I faced, I will explain the structure of these two tables first.
NB: The person who adds complaints is complaint owner & person who adds a complaint reply is complaint replier. Complaint owner can also add replies. So he can either be the complaint owner or the complaint replier. The two tables have a one-to-many relationship. A complaint can have more than one complaint reply. member_id in complaint table represents complaint owner & mem_id in complaints_reply represent complaint replier
DESIRED OUTPUT:
Join the two tables and fetch values and show the complaint and complaint’s reply as a single result set. But the condition is kinda tricky. The last added complaint reply from the complaints_reply table should be fetched for the complaint in complaints table in such a way that the complaint owner should not be the complaint replier. I use posted_date & posted_time from complaints_reply table to fetch the last added complaint reply for a complaint & that complaint replier has to be shown in the result set.
So, from the sample data the tables contain now, the output that I should get is:
+------+---------+----------+-------------+-------------------+
| id | title |member_id |last_replier |last_posted_dt |
+------+---------+----------+-------------+-------------------+
| 1 | x | 1000 |2002 | 2015-05-2610:11:17|
| 2 | y | 1001 |1000 | 2015-05-2710:06:16|
+------+---------+----------+-------------+-------------------+
But what I got is:
+------+---------+----------+-------------+-------------------+
| id | title |member_id |last_replier |last_posted_dt |
+------+---------+----------+-------------+-------------------+
| 1 | x | 1000 |1001 | 2015-05-2610:11:17|
| 2 | y | 1001 |2000 | 2015-05-2710:06:16|
+------+---------+----------+-------------+-------------------+
The date is correct, but the returned complaint replier last_replier is wrong.
This is my query.
SELECT com.id,
com.title,
com.member_id,
last_comp_reply.last_replier,
last_comp_reply.last_posted_dt
FROM complaints com
LEFT JOIN
(SELECT c.id AS complaint_id,
c.member_id AS parent_mem_id,
cr.mem_id AS last_replier,
max(cr.posted_dt) AS last_posted_dt
FROM
(SELECT cr.complaint_id,cr.mem_id,c.id,c.member_id,(CONCAT(cr.posted_date,cr.posted_time)) AS posted_dt
FROM complaints_reply cr,
complaints c
WHERE cr.complaint_id=c.id
AND cr.mem_id!=c.member_id
GROUP BY cr.complaint_id,
cr.mem_id,
posted_dt)cr,
complaints c
WHERE cr.complaint_id=c.id
GROUP BY cr.complaint_id,
c.id,
c.member_id) AS last_comp_reply ON com.id=last_comp_reply.complaint_id
Table structure for table complaints
CREATE TABLE IF NOT EXISTS `complaints` (
`id` int(11) NOT NULL,
`title` varchar(500) NOT NULL,
`member_id` int(11) NOT NULL,
`posted_date` date NOT NULL,
`posted_time` time NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
Indexes for table complaints
ALTER TABLE `complaints`
ADD PRIMARY KEY (`id`);
AUTO_INCREMENT for table complaints
ALTER TABLE `complaints`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;
Dumping data for table complaints
INSERT INTO `complaints` (`id`, `title`, `member_id`, `posted_date`, `posted_time`) VALUES
(1, 'x', 1000, '2015-05-05', '02:06:15'),
(2, 'y', 1001, '2015-05-14', '02:08:10');
Table structure for table complaints_reply
CREATE TABLE IF NOT EXISTS `complaints_reply` (
`id` int(11) NOT NULL,
`complaint_id` int(11) NOT NULL,
`comments` text NOT NULL,
`mem_id` int(11) NOT NULL,
`posted_date` date NOT NULL,
`posted_time` time NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
Indexes for table complaints_reply
ALTER TABLE `complaints_reply`
ADD PRIMARY KEY (`id`);
AUTO_INCREMENT for table complaints_reply
ALTER TABLE `complaints_reply`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=10;
Dumping data for table complaints_reply
INSERT INTO `complaints_reply` (`id`, `complaint_id`, `comments`, `mem_id`, `posted_date`, `posted_time`) VALUES
(1, 1, 'reply1', 2000, '2015-05-08', '02:07:08'),
(2, 1, 'reply2', 2001, '2015-05-06', '06:05:08'),
(3, 1, 'reply3', 1000, '2015-05-14', '02:12:13'),
(4, 2, 'hola', 1000, '2015-05-27', '10:06:16'),
(5, 2, 'hello', 2000, '2015-05-04', '03:09:09'),
(6, 2, 'gracias', 1001, '2015-05-31', '06:12:18'),
(7, 1, 'reply4', 1001, '2015-01-04', '04:08:12'),
(8, 2, 'puta', 1001, '2015-06-13', '06:12:18'),
(9, 1, 'reply5', 1000, '2015-06-01', '04:08:12'),
(10, 1, 'reply next', 2002, '2015-05-26', '10:11:17');
P.S.
To give an idea about what my query is all about, I'll explain the sub query that is used to combine the tables & give result based on the condition: complaint owner should not be the complaint replier is:
SELECT cr.complaint_id,
cr.mem_id,
c.id,
c.member_id,
(CONCAT(cr.posted_date,cr.posted_time)) AS posted_dt
FROM complaints_reply cr,
complaints c
WHERE cr.complaint_id=c.id
AND cr.mem_id!=c.member_id
GROUP BY cr.complaint_id,
cr.mem_id,
posted_dt
And the result for this is:
+--------------+---------+----------+-------------+-------------------+
| complaint_id | mem_id | id |member_id | posted_dt |
+--------------+---------+------- +-------------+-------------------+
| 1 | 1001 | 1 |1000 | 2015-01-0404:08:12|
| 1 | 2000 | 1 |1000 | 2015-05-0802:07:08|
| 1 | 2001 | 1 |1000 | 2015-05-0606:05:08|
| 1 | 2002 | 1 |1000 | 2015-05-2610:11:17|
| 2 | 1000 | 2 |1001 | 2015-05-2710:06:16|
| 2 | 2000 | 2 |1001 | 2015-05-0403:09:09|
+--------------+---------+----------+-------------+-------------------+
member_id here represents complaint owner and mem_id represents complaint replier
The inner query gives the result based on the condition, then everything after this goes haywire. I don't know where I made mistake. The complaint replies added by complaint owner is not fetched in this table. So far so good. Is there any alternative way to get the result from here?
This query gives the result.
SELECT com.id AS complaint_id,
com.member_id AS parent_mem_id,
crep.mem_id AS last_replier,
crl.last_posted_dt
FROM complaints com
LEFT JOIN complaints_reply crep ON com.id=crep.complaint_id
JOIN
(SELECT cr.complaint_id,
max(CONCAT(cr.posted_date,'_',cr.posted_time)) AS last_posted_dt
FROM complaints_reply cr,
complaints c
WHERE cr.complaint_id=c.id
AND cr.mem_id!=c.member_id
GROUP BY cr.complaint_id)crl ON CONCAT(crep.posted_date,'_',crep.posted_time)=crl.last_posted_dt
AND crep.complaint_id=crl.complaint_id