so I have this query
SELECT IF(c2.nid IS NULL, c.*, c2.*) FROM table1 c LEFT JOIN table1 c2 ON c.cid = c2.pid WHERE c.pid = 0 AND c.nid = 674662;
Notice that both c and c2 are referring to table1....basically, I want it so that if a left join entry exists, it will return the row in the left joined c2 whereas if it doesn't exists, it'll return the entries in c1...
However, executing this query will yield mysql syntax error..how do I go about accomplishing what im trying to accomplish (preferably in a single IF statement)?
I fear you can't use the star pattern within IF statement. So you need to explicitly type it out like
SELECT IF(c2.nid IS NULL, c.cid, c2.cid),
IF(c2.nid IS NULL, c.pid, c2.pid), ...
FROM table1 c LEFT JOIN table1 c2 ON c.cid = c2.pid
WHERE c.pid = 0 AND c.nid = 674662;
As #luksch answer, you can do this by using IF() or COALESCE() function on every column you need.
The only way that I can think of is with a UNION and splitting the two cases:
SELECT c2.*
FROM table1 c
INNER JOIN table1 c2 ON c.cid = c2.pid
WHERE c.pid = 0 AND c.nid = 674662
UNION ALL
SELECT c.*
FROM table1 c
LEFT JOIN table1 c2 ON c.cid = c2.pid
WHERE c.pid = 0 AND c.nid = 674662
AND c2.pid IS NULL ;
Related
I'm facing an issue where I have several tables joined, but I need to combine the e.url and f.url_new columns. Otherwise, the result is as expected. Here is my query.
SELECT a.`added_date`,b.`type`,c.`action`,e.`url`,f.`url_new`
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC
I've tried CONCAT, but the column contained all NULL values. Here's that query.
SELECT a.`added_date`,b.`type`,c.`action`,CONCAT(e.`url`,f.`url_new`) AS url
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC
Is there a minor modification I can make to this query to merge these columns?
try using CONCAT_WS() instead of CONCAT()
SELECT `CONCAT_WS(' ',e.url, f.url_new )` ....
CONCAT_WS() will concatenate the values if the values are not null.
From the manual of CONCAT()
CONCAT() returns NULL if any argument is NULL.
SELECT a.`added_date`,b.`type`,c.`action`,CONCAT_WS("", e.`url`,f.`url_new`) AS url
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC
I have that tables schema
via linq2Sql, I generate a query:
var types = (from d in TabD
where d.SomeID == myID
group d by d.TabC.TabB.TabA into g
select g.Key);
which generates that query
SELECT Distinct1.ID, Distinct1.Name
FROM (
SELECT DISTINCT ss.ID, ss.Name
FROM TabD AS d
INNER JOIN TabC AS c ON d.TabC_ID = c.ID
INNER JOIN TabB AS b ON c.TabB_ID = b.ID
LEFT OUTER JOIN TabA AS a ON b.TabA_ID = a.ID
WHERE sg.SomeID = 1
) AS Distinct1
which works, but why there is LEFT OUTER JOIN instead of INNER JOIN ?
You get LEFT JOIN whenever the foreign key on a table is nullable. If your database defines TabA_ID as TabA_ID int NULL it means TabB reference to TabA is not enforced.
Since it is not enforced based on your schema LINQ2SQL generates a LEFT join.
Hope this helps
I have a mysql query as stated below, it returns exactly the results I want for one row, but doesn't return any other rows where I expect there to be 8 in my test data (there are 8 unique test ids). I was inspired by this answer but obviously messed up my implementation, does anyone see where I'm going wrong?
SELECT
c.first_name,
c.last_name,
n.test_name,
e.doc_name,
e.email,
e.lab_id,
a.test_id,
a.date_req,
a.date_approved,
a.accepts_terms,
a.res_value,
a.reason,
a.test_type,
a.date_collected,
a.date_received,
k.kind_name,
sum(case when metabolite_name = "Creatinine" then t.res_val end) as Creatinine,
sum(case when metabolite_name = "Glucose" then t.res_val end) as Glucose,
sum(case when metabolite_name = "pH" then t.res_val end) as pH
FROM test_requisitions AS a
INNER JOIN personal_info AS c ON (a.user_id = c.user_id)
INNER JOIN test_types AS d ON (a.test_type = d.test_type)
INNER JOIN kinds AS k ON (k.id = d.kind_id)
INNER JOIN test_names AS n ON (d.name_id = n.id)
INNER JOIN docs AS e ON (a.doc_id = e.id)
INNER JOIN test_metabolites AS t ON (t.test_id = a.test_id)
RIGHT JOIN metabolites AS m ON (m.id = t.metabolite_id)
GROUP BY a.test_id
ORDER BY (a.date_approved IS NOT NULL),(a.res_value IS NOT NULL), a.date_req, c.last_name ASC;
Most of your joins are inner joins. The last is a right outer join. As written, the query keeps all the metabolites, but not necessarily all the tests.
I would suggest that you change them all to left outer joins, because you want to keep all the rows in the first table:
FROM test_requisitions AS a
LEFT JOIN personal_info AS c ON (a.user_id = c.user_id)
LEFT JOIN test_types AS d ON (a.test_type = d.test_type)
LEFT JOIN kinds AS k ON (k.id = d.kind_id)
LEFT JOIN test_names AS n ON (d.name_id = n.id)
LEFT JOIN docs AS e ON (a.doc_id = e.id)
LEFT JOIN test_metabolites AS t ON (t.test_id = a.test_id)
LEFT JOIN metabolites AS m ON (m.id = t.metabolite_id)
I would also suggest that your aliases be related to the table, so tr for test_requisition, pi for personal_info, and so on.
Here's a picture of my database structure:
With help from users on here I've managed to put together quite a complex SQL statement using GROUP_CONCAT:
SELECT
t1.Name AS Teacher_Name,
t2.Name AS Observer_Name,
o.Datetime AS Datetime,
o.Type AS Type,
o.Year_Group AS Year_Group,
o.Class_Name AS Class_Name,
c.Title AS Course_Name,
GROUP_CONCAT(l.Title) AS Focus,
o.Achievement_Grade AS Achievement_Grade,
o.Behaviour_Grade AS Behaviour_Grade,
o.Teaching_Grade AS Teaching_Grade,
GROUP_CONCAT(cl1.Title) AS Positive,
GROUP_CONCAT(cl2.title) AS Development,
o.Notes AS Notes
FROM observations o
LEFT JOIN teachers t1
ON o.Teacher_ID = t1.Teacher_ID
LEFT JOIN teachers t2
ON o.Observer_ID = t2.Teacher_ID
LEFT JOIN courses c
ON o.Course_ID = c.Course_ID
LEFT JOIN foci f
ON o.ID = f.Observation_ID
LEFT JOIN focus_labels l
on f.focus_id = l.id
LEFT JOIN criteria c1
ON o.ID = c1.Observation_ID
LEFT JOIN criteria_labels cl1
on c1.Criteria_ID = cl1.ID AND c1.Type = 'P'
LEFT JOIN criteria c2
ON o.ID = c2.Observation_ID AND c2.Type = 'D'
LEFT JOIN criteria_labels cl2
on c2.Criteria_ID = cl2.ID
GROUP BY o.id
ORDER BY `Datetime` DESC";
This appears to work OK, apart from the fact that Focus, Positive and Development are each repeated depending on the field that has the highest number of concatenations in.
For example, if Positive has Pace,Progress,Attainment but Focus is only Appraisal, it'll be repeated three times (Appraisal,Appraisal,Appraisal).
I've looked this up and I think it could be because I need to GROUP each of these GROUP_CONCAT JOINs. However, I have no idea how to go about this.
Can anyone help? Thanks in advance,
GROUP_CONCAT has DISTINCT attribute that can be applied to remove duplicates.
SELECT
t1.Name AS Teacher_Name,
t2.Name AS Observer_Name,
o.Datetime AS Datetime,
o.Type AS Type,
o.Year_Group AS Year_Group,
o.Class_Name AS Class_Name,
c.Title AS Course_Name,
GROUP_CONCAT(DISTINCT l.Title) AS Focus,
o.Achievement_Grade AS Achievement_Grade,
o.Behaviour_Grade AS Behaviour_Grade,
o.Teaching_Grade AS Teaching_Grade,
GROUP_CONCAT(cl1.Title) AS Positive,
GROUP_CONCAT(cl2.title) AS Development,
o.Notes AS Notes
FROM observations o
LEFT JOIN teachers t1
ON o.Teacher_ID = t1.Teacher_ID
LEFT JOIN teachers t2
ON o.Observer_ID = t2.Teacher_ID
LEFT JOIN courses c
ON o.Course_ID = c.Course_ID
LEFT JOIN foci f
ON o.ID = f.Observation_ID
LEFT JOIN focus_labels l
on f.focus_id = l.id
LEFT JOIN criteria c1
ON o.ID = c1.Observation_ID
LEFT JOIN criteria_labels cl1
on c1.Criteria_ID = cl1.ID AND c1.Type = 'P'
LEFT JOIN criteria c2
ON o.ID = c2.Observation_ID AND c2.Type = 'D'
LEFT JOIN criteria_labels cl2
on c2.Criteria_ID = cl2.ID
GROUP BY o.id
ORDER BY `Datetime` DESC";
This is the query I'm performing (without some Joins that are not relevant):
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id
Each row of "a" is linked with 1 to 5 rows in "b".
The problem is that GROUP BY has performance issues (it takes 10x or more using GROUP BY than not using it). I need to retrieve only one row of each member in "a".
How can I make this faster?
edit: I need to be able to filter by a.id AND/OR c.id. The resultset I should be getting is only 1 row per "valid" member of "a", meaning the rows that match the constraints. Rows that don't match the filters shouldn't be returned.
In my original query, this would be done this way:
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id
a.id, b.id_anunciante, b.id_rubro, c.id are all indexes.
SELECT a.*,
(
SELECT c.id
FROM b
JOIN с
ON c.id = b.id_rubro
WHERE b.id_anunciante = a.id
-- add the ORDER BY condition to define which row will be selected.
LIMIT 1
)
FROM a
Create the index on b (id_anunciante) for this to work faster.
Update:
You don't need the OUTER JOINs here.
Rewrite your query as this:
SELECT a.*, c.id
FROM a
JOIN b
ON b.id_anunciante = a.id
JOIN c
ON c.id = b.id_rubro
WHERE a.id = 1
UNION ALL
SELECT a.*, 1
FROM a
WHERE EXISTS
(
SELECT NULL
FROM c
JOIN b
ON b.id_rubro = c.id
WHERE c.id = 1
AND b.id_anunciante = a.id
)
Add ORDER BY NULL to avoid the implicit sorting MySQL does when doing a group by.
I suppose you have indexes/PKs on a.id, b.id_anunciante, b.id_rubro and c.id ? I guess you could try adding a composite index on (b.id_anunciante, b.id_rubro) if your mysql version is not able to do an index merge.