How to make query - mysql

review table has store_idx, user_idx etc...
I want to create a query sentence that gets information about the store to which the user has bookmarked with the user_id value entered.
The query sentence I made is
select A.store_name
, A.store_img
, count(B.store_idx) as review_cnt
from board.store A
Left
Join board.review B
On A.store_idx is B.store_idx
where store_idx is (select A.store_idx from bookmark where user_id = ?)
However, nothing came out as a result.
Help me..

Please use below Query:
SELECT store_name
, store_img
, SUM(review_cnt) AS review_cnt
FROM
( SELECT DISTINCT A.store_name
, A.store_img
, CASE WHEN B.store_idx IS NULL THEN 0 ELSE 1 END AS review_cnt
FROM bookmark br
JOIN board.store A
ON A.store_idx = br.store_idx
LEFT
JOIN board.review B
ON A.store_idx = B.store_idx
WHERE br.user_id = ?
)T

The WHERE clause is obviously filtering out all rows. We can't do much about that. But your query is also lacking a GROUP BY, the table aliases can be improved, and the join condition is not correct.
So, try this version:
select s.store_name, s.store_img, count(b.store_idx) as review_cnt
from board.store s left join
board.review r
on s.store_idx = r.store_idx
where b.store_idx in (select b.store_idx
from bookmark b
where b.user_id = ?
);

Related

Remove Duplicate rows in left join base on one column

I want to remove the duplicates column with the same id. I want to keep only the first one that shows up.
SELECT t.ticketId ,t.userIdOwner , t.ticketCreateDatetime , t.ticketExpectedEndDatetime , t.ticketUpdateDatetime, t.ticketUpdateBy, t.ticketLabel,t.statusTypeIdTicketState,t.statusTypeIdTicketType,t.statusTypeIdTicketModule,
c.clientLabel, c.clientLogoOnList ,s.taskLabel , s.statusTypeIdTaskCompletion
FROM ticket AS t
INNER JOIN client AS c
ON c.clientId = t.clientId
LEFT JOIN task AS s
ON s.ticketId = t.ticketId AND s.statusTypeIdTaskCompletion = (SELECT statusTypeId FROM statusType WHERE statusTypeCode = 'waitingTask' AND statusTypeTargetTable = 'statusTypeIdTaskCompletion' )
WHERE 1=1
AND t.ticketDeleteDatetime IS NULL
Here's my screen of results
Edit Image query all results
enter image description here
Edit Image of task structure table :
enter image description here
You probably have more tasks for each ticket with same statusType
so, if you don't care about different tasks, you can simply add a DISTINCT clause in your SELECT
SELECT DISTINCT
t.ticketId ,t.userIdOwner , t.ticketCreateDatetime , t.ticketExpectedEndDatetime ,
t.ticketUpdateDatetime, t.ticketUpdateBy, t.ticketLabel,t.statusTypeIdTicketState,
t.statusTypeIdTicketType,t.statusTypeIdTicketModule,
c.clientLabel, c.clientLogoOnList ,s.taskLabel , s.statusTypeIdTaskCompletion
FROM ticket AS t
INNER JOIN client AS c ON c.clientId = t.clientId
LEFT JOIN task AS s ON s.ticketId = t.ticketId AND s.statusTypeIdTaskCompletion = (
SELECT statusTypeId
FROM statusType
WHERE statusTypeCode = 'waitingTask'
AND statusTypeTargetTable = 'statusTypeIdTaskCompletion'
)
WHERE 1=1
AND t.ticketDeleteDatetime IS NULL
ok, after your edit, now we can see, that the problem is that more than one task is eligible for the ticket.
Unfortunaterly "the first that show up" is not a valid SQL statement (because the same query could give different results depending on different circumnstances).
So you have to decide wich one to keep, you need to decide a rule, a logic to keep one of the rows.
If you don't need the task label you can simply strip off that column and use the DISTINCT.
If you want to show a task label but don't mind which one, you can use MAX(s.taskLabel) and group by on all other columns.
If you want to keep the last task for that ticket you should provide informations about cronological order (a datetime column or an autoincrement column)
Example with MAX(taskLabel):
SELECT
t.ticketId,
t.userIdOwner,
t.ticketCreateDatetime,
t.ticketExpectedEndDatetime,
t.ticketUpdateDatetime,
t.ticketUpdateBy,
t.ticketLabel,
t.statusTypeIdTicketState,
t.statusTypeIdTicketType,
t.statusTypeIdTicketModule,
c.clientLabel,
c.clientLogoOnList,
s.taskLabel,
s.statusTypeIdTaskCompletion
FROM ticket AS t
INNER JOIN client AS c ON c.clientId = t.clientId
LEFT JOIN (
SELECT s.ticketId, MAX(s.taskLabel) AS taskLabel
FROM task AS s
WHERE s.statusTypeIdTaskCompletion = (
SELECT statusTypeId
FROM statusType
WHERE statusTypeCode = 'waitingTask'
AND statusTypeTargetTable = 'statusTypeIdTaskCompletion'
)
GROUP BY s.ticketId
) S ON s.ticketId = t.ticketId
WHERE 1=1
AND t.ticketDeleteDatetime IS NULL

How to use 'Mysql JOIN' with sql text of same table

I want to use mysql's "JOIN"
I want to group rows by "date_text" where "tokenIdx" is "1001" and "datetime_unix" is the highest value.
Is my code wrong?
SELECT `A.idx`
FROM `data_candle_h1` 'A'
JOIN
(
SELECT `date_text`, MAX(`datetime_unix`) AS 'datetime_unix'
FROM `data_candle_h1`
WHERE `tokenIdx` = '1002'
GROUP BY `date_text`
) 'B'
ON `A.datetime_unix` = `B.datetime_unix`
WHERE `A.tokenIdx` = '1002'
Your query is syntactically perfect. Just remove single quotes('') around table aliases (A and B). I have corrected it. Please check this out.
SELECT `A.idx`
FROM `data_candle_h1` A
JOIN
(
SELECT `date_text`, MAX(`datetime_unix`) AS 'datetime_unix'
FROM `data_candle_h1`
WHERE `tokenIdx` = '1002'
GROUP BY `date_text`
) B
ON `A.datetime_unix` = `B.datetime_unix`
WHERE `A.tokenIdx` = '1002'

Order query output according to 'is in table/ is not in table'

I have the following Database Design:
Database Design
I want to get all Information from table 'info' where the id IS NOT in table 'archived'. To do so I wrote:
SELECT *
FROM traffic_info i
LEFT JOIN
traffic_info_archived a ON (i.info_id = a.info_id)
WHERE
i.branch_id = 4 AND i.user_id = 7 a.info_id IS NULL ORDER BY i.info_date_from ASC
This works as expected.
The next challenge is to only show information that are also included in the 'published' table. To get this done I have expanded my previous query to :
SELECT *
FROM traffic_info i
LEFT JOIN
traffic_info_archived a ON (i.info_id = a.info_id)
RIGHT JOIN
traffic_info_publised p ON (i.info_id = p.info_id)
WHERE
i.branch_id = 4 AND a.info_id AND i.user_id = 7 IS NULL ORDER BY i.info_date_from ASC
This does also work as expected.
The final challenge is to Order this result according to table 'read'. Information´s id that are NOT in table 'read' should be ordered ASC. But even if its id does not appear in table 'read' they should not be excluded from the query output. BUT the primary ORDER should be
i.info_date_from ASC
I hope this is understandable, my English is not the best :) If not, please comment and I will do my best to make it understandable. Hope some can help!
I´ve tried to create a SQLFiddle, but I wasn´t able to create a runnable example, sorry for that.
UPADTE:
Using the approach from #Dylan Su
SELECT *
FROM traffic_info i
LEFT JOIN
traffic_info_archived a ON (i.info_id = a.info_id)
INNER JOIN
traffic_info_publised p ON (i.info_id = p.info_id)
WHERE
i.branch_id = 4 AND a.info_id AND i.user_id = 7 IS NULL
ORDER BY
CASE WHEN NOT EXISTS(SELECT 1 FROM read WHERE i.info_id = read.info_id)
THEN i.info_date_from END ASC;
the goal is nearer then it ever was :)
Sample Data output
Both entries marked with a red "X" are in table read. Therefore id 3 should be last the, in the middle 1 and 2 at the top.
So the last thing to archive is to do the correct order of table read. I´ve tried sth like:
(SELECT 1 FROM traffic_info_read WHERE i.info_id = traffic_info_read.info_id ORDER BY traffic_info_read.info_id DESC)
But that didn´t had any influnce.
Try this:
SELECT *
FROM traffic_info i
LEFT JOIN
traffic_info_archived a ON (i.info_id = a.info_id)
INNER JOIN
traffic_info_publised p ON (i.info_id = p.info_id)
WHERE
i.branch_id = 4 AND a.info_id AND i.user_id = 7 IS NULL
ORDER BY
EXISTS(SELECT 1 FROM read WHERE i.info_id = read.info_id) ASC,
i.info_date_from ASC;
The Answer of #Dylan Su is absolutely correct and I won´t unmark it as accepted.
However, based on the Information I gained from the conversation I have created another solution, that doesn´t make use of sub query.
I heard that using just JOIN´s will result in better performance, I don´t know if it´s correct and I don´t have that much test data currently to find out, but here is the solution using no sub query.
SELECT *
FROM traffic_info i
LEFT JOIN
traffic_info_archived a ON (i.info_id = a.info_id)
INNER JOIN
traffic_info_published p ON (i.info_id = p.info_id)
LEFT JOIN
traffic_info_read r ON (i.info_id = r.info_id)
WHERE
i.branch_id = 4 AND a.info_id IS NULL ORDER BY r.info_id IS NULL DESC, i.info_date_from ASC
;

better way of doing this SELECT in MySQL

Best way to do this SELECT?
I've got this tables:
t_department
id
name
t_users
id
name
type
*type can be:
1 SuperUser
2 normalUser
t_department_superuser
(A department can have many superUsers)
-idSuperUser
-idDepartment
t_superuser_normaluser
(A superUser can have many normalusers)
-idSuperUser
-idNormalUser
and finally
t_actions
-id (autonumeric)
-idUser (this can be an id of superUser or normalUser)
-action
Given a department name, for example "mainDepartment"
I need to get all records from t_actions of all normalusers and all superusers of that department
I have this, it works, but I am not an SQL expert (I am using MySQL) and I think it is not the best way to do the select, and t_actions is going to have loads of rows:
SELECT id,idUser,action
FROM t_actions
WHERE (idUser IN (
SELECT DISTINCT t_department_superuser.idSuperUser FROM t_department
RIGHT JOIN t_department_superuser ON t_department_superuser.idDepartment = t_department.id
LEFT JOIN t_superuser_normaluser ON t_superuser_normaluser.idSuperUser = t_department_superuser.idSuperUser
WHERE name='mainDepartment'
UNION ALL
SELECT DISTINCT t_superuser_normaluser.idNormalUser
FROM t_department
RIGHT JOIN t_department_superuser ON t_department_superuser.idDepartment = t_department.id
LEFT JOIN t_superuser_normaluser ON t_superuser_normaluser.idSuperUser = t_department_superuser.idSuperUser
WHERE name='mainDepartment')
ORDER BY id;
Any suggestions to make this better? thank you!!
because you are using left and right joins there will be null records, which is why you need the UNION... you can cut out the UNION with a simple null check
SELECT id, idUser, action
FROM t_actions
WHERE idUser IN
( SELECT DISTINCT COALESCE(tsn.idNormalUser, tds.idSuperUser)
FROM t_department td
RIGHT JOIN t_department_superuser tds ON tds.idDepartment = td.id
LEFT JOIN t_superuser_normaluser tsn ON tsn.idSuperUser = tds.idSuperUser
WHERE td.name='mainDepartment'
)
ORDER BY id;
note i also added alias's to your table names so its easer to write out and read the columns you are trying to select and join on.
EDIT
with the data the only possible way to do it with this table design is like this
SELECT id, idUser, action
FROM t_actions
WHERE idUser IN
((SELECT tds.idSuperUser
FROM t_department td
JOIN t_department_superusers tds ON tds.idDepartment = td.id
WHERE td.name='MAIN')
UNION
(SELECT tsn.idNormalUser
FROM t_department td
JOIN t_department_superusers tds ON tds.idDepartment = td.id
JOIN t_superuser_normaluser tsn ON tsn.idSuperUser = tds.idSuperUser
WHERE td.name='MAIN')
)
ORDER BY id;

SQL: Get latest entries from history table

I have 3 tables
person (id, name)
area (id, number)
history (id, person_id, area_id, type, datetime)
In this tables I store the info which person had which area at a specific time. It is like a salesman travels in an area for a while and then he gets another area. He can also have multiple areas at a time.
history type = 'I' for CheckIn or 'O' for Checkout.
Example:
id person_id area_id type datetime
1 2 5 'O' '2011-12-01'
2 2 5 'I' '2011-12-31'
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31.
Now I want to have a list of all the areas all persons have right now.
person1.name, area1.number, area2.number, area6.name
person2.name, area5.number, area9.number
....
The output could be like this too (it doesn't matter):
person1.name, area1.number
person1.name, area2.number
person1.name, area6.number
person2.name, area5.number
....
How can I do that?
This question is, indeed, quite tricky. You need a list of the entries in history where, for a given user and area, there is an 'O' record with no subsequent 'I' record. Working with just the history table, that translates to:
SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime)
FROM History AS ho
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
)
GROUP BY ho.person_id, ho.area_id, ho.type;
Then, since you're really only after the person's name and the area's number (though why the area number can't be the same as its ID I am not sure), you need to adapt slightly, joining with the extra two tables:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
);
The NOT EXISTS clause is a correlated sub-query; that tends to be inefficient. You might be able to recast it as a LEFT OUTER JOIN with appropriate join and filter conditions:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
LEFT OUTER JOIN History AS hi
ON hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
WHERE ho.type = 'O'
AND hi.person_id IS NULL;
All SQL unverified.
You're looking for results where each row may have a different number of columns? I think you may want to look into GROUP_CONCAT()
SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id`
I haven't tested this query, but I have used group concat in similar ways before. Naturally, you will want to tailor this to fit your needs. Of course, group concat will return a string so it will require post processing to use the data.
EDIT I thikn your question has been edited since I began responding. My query does not really fit your request anymore...
Try this:
select *
from person p
inner join history h on h.person_id = p.id
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O'
inner join areas on a.id = h.area_id
where h2.person_id is null and h.type = 'I'