Common results of two MySQL queries - mysql

I am looking to combine two MySQL queries so it returns the common results so I know I am not looking to use UNION on this one. I tried writing a subselect statement but that didn't work out
First query:
SELECT s.ses_id, h.page, m.question, m.answer FROM session s
INNER JOIN history h on h.ses_id = s.ses_id
INNER JOIN multiple m on m.ses_id = s.ses_id
WHERE m.question = 4 and m.answer = 3 and h.page = 4
Second query:
SELECT s.ses_id, h.page, m.question, m.answer FROM session s
INNER JOIN history h on h.ses_id = s.ses_id
INNER JOIN multiple m on m.ses_id = s.ses_id
WHERE m.question = 114 and m.answer = 1 and h.page = 114
Failed merge query:
SELECT s.ses_id FROM session s, multiple, history h
JOIN (
SELECT session.ses_id
FROM session, history, multiple
WHERE multiple.question = 114 and multiple.answer = 1 and history.page = 114 and history.ses_id = session.ses_id and multiple.ses_id=session.ses_id
) q1 ON q1.ses_id = s.ses_id
WHERE s.interview = 'lifestyle' and s.finished = 'y' and multiple.page=4 and multiple.answer = 3 and h.page = 4 and h.ses_id = s.ses_id and multiple.ses_id=s.ses_id
The multiple table contains questions and answers and I am looking to find the ids of those who have answered the two questions with those specific answers.
I realize this should be easy and I am most likely overthinking and/or missing something.

You simply need to join both the history and multiple tables an additional time each for the 2nd question/answer combination.
SELECT s.ses_id,
m1.question, m1.answer, h1.page,
m2.question, m2.answer, h2.page
FROM session s
INNER JOIN history h1
ON h1.ses_id = s.ses_id AND h1.page = 4
INNER JOIN multiple m1
ON m1.ses_id = s.ses_id
AND m1.question = 4 AND m1.answer = 3
INNER JOIN history h2
ON h2.ses_id = s.ses_id AND h2.page = 114
INNER JOIN multiple m2
ON m2.ses_id = s.ses_id
AND m2.question = 114 and m2.answer = 1
WHERE s.interview = 'lifestyle' and s.finished = 'y'

Below simply altered query may be useful.,
SELECT s.ses_id, h.page, m.question, m.answer FROM session s
INNER JOIN history h on h.ses_id = s.ses_id
INNER JOIN multiple m on m.ses_id = s.ses_id
WHERE
( m.question = 4 and m.answer = 3 and h.page = 4 )
OR
( m.question = 114 and m.answer = 1 and h.page = 114 )
Merge operation is not needed.

if you are looking for intersection of two queries then you can simply use IN set operator of mysql
SELECT s.ses_id, h.page, m.question, m.answer
FROM session s
INNER JOIN history h on h.ses_id = s.ses_id
INNER JOIN multiple m on m.ses_id = s.ses_id
WHERE m.question = 4 and m.answer = 3 and h.page = 4 and s.ses_id
IN
(
SELECT s.ses_id
FROM session s
INNER JOIN history h on h.ses_id = s.ses_id
INNER JOIN multiple m on m.ses_id = s.ses_id
WHERE m.question = 114 and m.answer = 1 and h.page = 114
)

Related

MySQL query with many joins

I have query with many joins and I'm searching for optimization for it.
It's about computers:
For examples I have:
Lenovo 8gbRAM 1TB core i5 ips etc. (all these after brand name are attributes)
I have configuration where, I want to change attribute 8gbRAM to 16gbRAM and I have to search for other item with all these attributes and 16gbRAM
Two tables:
**st_item**
- id
- name
...
**st_item_specification_attribute**
- id
- st_item_id
- attribute_id
- attribute_value_id
...
My problem is that my item has 15 attributes. When I tested with lower number of attributes I use this structure of query and it works, but now system has 85k items and over 1kk item attributes
This is the query:
SELECT `st_item`.id FROM `st_item`
LEFT JOIN `st_item_specification_attribute` `sisa_36590` ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
LEFT JOIN `st_item_specification_attribute` `sisa_367910` ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
LEFT JOIN `st_item_specification_attribute` `sisa_374641` ON st_item.id = sisa_374641.item_id AND sisa_374641.attribute_id = 374
LEFT JOIN `st_item_specification_attribute` `sisa_378366` ON st_item.id = sisa_378366.item_id AND sisa_378366.attribute_id = 378
LEFT JOIN `st_item_specification_attribute` `sisa_382500` ON st_item.id = sisa_382500.item_id AND sisa_382500.attribute_id = 382
LEFT JOIN `st_item_specification_attribute` `sisa_372134` ON st_item.id = sisa_372134.item_id AND sisa_372134.attribute_id = 372
LEFT JOIN `st_item_specification_attribute` `sisa_41268` ON st_item.id = sisa_41268.item_id AND sisa_41268.attribute_id = 412
LEFT JOIN `st_item_specification_attribute` `sisa_413368` ON st_item.id = sisa_413368.item_id AND sisa_413368.attribute_id = 413
LEFT JOIN `st_item_specification_attribute` `sisa_414929` ON st_item.id = sisa_414929.item_id AND sisa_414929.attribute_id = 414
LEFT JOIN `st_item_specification_attribute` `sisa_418496` ON st_item.id = sisa_418496.item_id AND sisa_418496.attribute_id = 418
LEFT JOIN `st_item_specification_attribute` `sisa_385748` ON st_item.id = sisa_385748.item_id AND sisa_385748.attribute_id = 385
LEFT JOIN `st_item_specification_attribute` `sisa_36625` ON st_item.id = sisa_36625.item_id AND sisa_36625.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366355` ON st_item.id = sisa_366355.item_id AND sisa_366355.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366816` ON st_item.id = sisa_366816.item_id AND sisa_366816.attribute_id = 366
LEFT JOIN `st_item_specification_attribute` `sisa_366370` ON st_item.id = sisa_366370.item_id AND sisa_366370.attribute_id = 366
WHERE (`parent_id`=1032) AND
(sisa_36590.attribute_value_id = 2230) AND
(sisa_367910.attribute_value_id = 2451) AND
(sisa_374641.attribute_value_id = 3793) AND
(sisa_378366.attribute_value_id = 2955) AND
(sisa_382500.attribute_value_id = 3879) AND
(sisa_372134.attribute_value_id = 2780) AND
(sisa_41268.attribute_value_id = 3363) AND
(sisa_413368.attribute_value_id = 3373) AND
(sisa_414929.attribute_value_id = 3378) AND
(sisa_418496.attribute_value_id = 3844) AND
(sisa_385748.attribute_value_id = 3036) AND
(sisa_36625.attribute_value_id = 2315) AND
(sisa_366355.attribute_value_id = 2408) AND
(sisa_366816.attribute_value_id = 2412) AND
(sisa_366370.attribute_value_id = 2420)
Query must compare specific pair attribute_id => attribute_value_id, that's the reason my "ON clause" to be with item_id and attribute_id and specific alias
You can use aggregation:
select i.id
from st_item i join
st_item_specification_attribute sisa
ON sisa.item_id = i.item_id
where i.parent_id = 1032 and
(sisa.attribute_id, attribute_value_id) in ( (365, 2230), (367, 2451), . . .)
group by i.id
having count(*) = 15;
You can move your WHERE conditions into ON conditions
and change LEFT JOIN to INNER JOIN.
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa_36590`
ON st_item.id = sisa_36590.item_id AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
JOIN `st_item_specification_attribute` `sisa_367910`
ON st_item.id = sisa_367910.item_id AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
...
WHERE `parent_id`=1032
2nd approach
SELECT `st_item`.id FROM `st_item`
JOIN `st_item_specification_attribute` `sisa`
ON st_item.id = sisa.item_id AND
(
(sisa.attribute_id = 365 AND sisa.attribute_value_id = 2230)
OR
(sisa.attribute_id = 367 AND sisa.attribute_value_id = 2451)
...
)
WHERE `parent_id`=1032
GROUP BY `st_item`.id
HAVING COUNT(*) = 15
I cannot predict the performance, but I think you could make on subselect out of all that joins
(I presume atribute_id and Attribute_value_id pairs are unique per item_id)
SELECT `st_item`.id FROM `st_item`
WHERE (`parent_id`=1032) AND
15 = (SELECT COUNT(*) FROM st_item_specification_attribute attr
WHERE `st_item`.id = attr.item_id
AND ( attribute_id = 365 AND attribute_value_id = 2230 OR
...
)
I would use a UNION ALL approach for this. It's easy to change, and fairly simple to read. Performance should be pretty good too:
--A CTE so you only have to change parent_id in one place
--I believe not all mysql versions support this, though
--You could of course just select the parent_id in de UNION ALL and
-- use a single WHERE in the outer query.
WITH st_item_id AS
(
SELECT id
, attribute_id
, attribute_value_id
FROM st_item
WHERE parent_id = 1032
)
SELECT UA.id
FROM (
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_36590
ON st_item_id.id = sisa_36590.item_id
AND sisa_36590.attribute_id = 365
AND sisa_36590.attribute_value_id = 2230
UNION ALL
SELECT st_item.id
FROM st_item_id
INNER JOIN st_item_specification_attribute sisa_367910
ON st_item_id.id = sisa_367910.item_id
AND sisa_367910.attribute_id = 367
AND sisa_367910.attribute_value_id = 2451
) UA

Combining results of two queries into one query

I am trying to combine two queries into a single one. But I am not having any success in it.
Query1:
SELECT
District.PkLocID AS districtId,
District.LocName AS districtName,
COUNT(DISTINCT UC.PkLocID) AS reported
FROM
tbl_locations AS District
INNER JOIN tbl_locations AS UC ON District.PkLocID = UC.district_id
INNER JOIN tbl_warehouse ON UC.PkLocID = tbl_warehouse.locid
INNER JOIN tbl_wh_data ON tbl_warehouse.wh_id = tbl_wh_data.wh_id
INNER JOIN stakeholder ON tbl_warehouse.stkofficeid = stakeholder.stkid
WHERE
stakeholder.lvl = 6
AND tbl_warehouse.stkid = 1
AND District.province_id = 1
AND tbl_wh_data.report_month = 02
AND tbl_wh_data.report_year = 2014
AND tbl_wh_data.wh_issue_up IS NOT NULL
GROUP BY
District.PkLocID
ORDER BY
districtId ASC
Query 2:
SELECT
COUNT(DISTINCT UC.PkLocID) AS totalWH,
District.PkLocID
FROM
tbl_locations AS District
INNER JOIN tbl_locations AS UC ON District.PkLocID = UC.district_id
INNER JOIN tbl_warehouse ON UC.PkLocID = tbl_warehouse.locid
INNER JOIN stakeholder ON tbl_warehouse.stkofficeid = stakeholder.stkid
WHERE
stakeholder.lvl = 6
AND tbl_warehouse.stkid = 1
AND District.province_id = 1
GROUP BY
District.PkLocID
ORDER BY
District.PkLocID ASC
I have tried applying subqueries and joins but it is showing me incorrect results.

MYSQL with SUM results and GROUP BY

I've got this query and I want to SUM all the results of the query grouped by the column omschrijving.
The query
SELECT b.BoekRegelBedrag as total, c.omschrijving, ctl.vd1, b.BoekRegelId
FROM condensations as c
LEFT JOIN condensations_to_ledgers as ctl
ON ctl.vd1 = c.code
LEFT JOIN BoekstukRegels as b
ON b.BoekRegelGrootboekNr = ctl.GrootboekNummer
LEFT JOIN GrootboekRekeningen as g
ON g.GrootboekNummer = ctl.GrootboekNummer
WHERE c.bedrijf_id = 118
AND b.BoekregelUserId = 118
AND ctl.bedrijf_id = 118
AND g.GrootboekUserId = 118
AND c.code < 10
AND g.BaSoort = 2
AND b.BoekRegelPeriode BETWEEN 201000 AND 201013
GROUP BY b.BoekRegelId
Is there a simple way to do this?
EDIT
I tried to SUM BoekRegelBedrag but then each record sums up a part in one way or the other and i got 4 results instead of one result with the total of the summed column
Since you've not clearly stipulated which column(s) should be summed, we have to guess. Assuming that the BoekRegelId column should not be summed (it seldom makes sense to do arithmetic on ID numbers) — and then not summing ctl.vd1 per comment — then:
SELECT omschrijving, SUM(total) AS sum_total
FROM (SELECT b.BoekRegelBedrag as total, c.omschrijving, ctl.vd1, b.BoekRegelId
FROM condensations AS c
LEFT JOIN condensations_to_ledgers AS ctl
ON ctl.vd1 = c.code
LEFT JOIN BoekstukRegels AS b
ON b.BoekRegelGrootboekNr = ctl.GrootboekNummer
LEFT JOIN GrootboekRekeningen AS g
ON g.GrootboekNummer = ctl.GrootboekNummer
WHERE c.bedrijf_id = 118
AND b.BoekregelUserId = 118
AND ctl.bedrijf_id = 118
AND g.GrootboekUserId = 118
AND c.code < 10
AND g.BaSoort = 2
AND b.BoekRegelPeriode BETWEEN 201000 AND 201013
GROUP BY b.BoekRegelId
) AS I
GROUP BY omschrijving;
Basically, I'm using your original query result as a 'table' in the FROM clause, and then aggregating on its columns in a way which might be what you're after.
An alternative, simpler approach may also be feasible if the core query is close to what you wanted:
SELECT c.omschrijving, SUM(b.BoekRegelBedrag) as total
FROM condensations AS c
LEFT JOIN condensations_to_ledgers AS ctl ON ctl.vd1 = c.code
LEFT JOIN BoekstukRegels AS b ON b.BoekRegelGrootboekNr = ctl.GrootboekNummer
LEFT JOIN GrootboekRekeningen AS g ON g.GrootboekNummer = ctl.GrootboekNummer
WHERE c.bedrijf_id = 118
AND b.BoekregelUserId = 118
AND ctl.bedrijf_id = 118
AND g.GrootboekUserId = 118
AND c.code < 10
AND g.BaSoort = 2
AND b.BoekRegelPeriode BETWEEN 201000 AND 201013
GROUP BY c.omschrijving;

Is it possible to turn this query into a join?

This is the query:
SELECT *
FROM square_achievements_achievements
JOIN square_achievements_achievement_counters ON square_achievements_achievement_counters.SAA_ID = square_achievements_achievements.SAA_ID
JOIN square_achievements_counters ON square_achievements_counters.SAC_ID = square_achievements_achievement_counters.SAC_ID
WHERE square_achievements_counters.eventObject = 'CommentEvent'
AND square_achievements_counters.eventType = 'add'
AND square_achievements_achievements.SAA_ID NOT IN
(
SELECT square_achievements_achievements.SAA_ID
FROM square_achievements_achievements
JOIN square_achievements_user_achievements ON square_achievements_user_achievements.SAA_ID = square_achievements_achievements.SAA_ID
WHERE square_achievements_user_achievements.UID = 83
)
If it's possible, would it be more efficient to write this query as a join? If so, how would it be rewritten?
SELECT a.*
FROM achievements a
JOIN achievement_counters ac
ON ac.saac_id = a.saa_id
JOIN counters c
ON c.sac_id = ac.sac_id
WHERE c.eventObject = 'CommentEvent'
AND c.eventType = 'add'
AND a.saa_id NOT IN
(
SELECT saa_id
FROM user_achievements
WHERE uid = 83
)
This is pretty good.
If you want joins, use this:
SELECT a.*
FROM achievements a
JOIN achievement_counters ac
ON ac.saac_id = a.saa_id
JOIN counters c
ON c.sac_id = ac.sac_id
LEFT JOIN
user_achievements ua
ON ua.uid = 83
AND ua.saa_id = a.saa_id
WHERE c.eventObject = 'CommentEvent'
AND c.eventType = 'add'
AND ua.saa_id IS NULL
I prefer to use correlation names to improve the readability of the code
Try this:
SELECT *
FROM square_achievements_achievements a
JOIN square_achievements_achievement_counters b ON b.SAAC_ID = a.SAA_ID
JOIN square_achievements_counters c ON c.SAC_ID = b.SAC_ID
JOIN square_achievements_user_achievements d on d.SAA_ID = a.SAA_ID
JOIN square_achievements_user_achievements u on d.SAA_ID = u.SAA_ID AND u.UID = 83
WHERE c.eventObject = 'CommentEvent'
AND a.eventType = 'add'

mysql select query

I've got 2 tables: interviews & interview_keywords.
An interview has 5 sorted keywords. I need a list of interviews with specified keywords in the right positions of the sorted list. This is what I've got so far, which isn't working:
SELECT i.id,
i.title
FROM interviews AS i
LEFT JOIN interview_keywords AS ik ON i.id = ik.interview_id
WHERE i.cat_id = 1
AND ( (ik.keyword_id = 39 AND ik.sort = 1)
AND (ik.keyword_id = 33 AND ik.sort = 2)
AND (ik.keyword_id = 51 AND ik.sort = 3)
AND (ik.keyword_id = 96 AND ik.sort = 4)
AND (ik.keyword_id = 97 AND ik.sort = 5))
SELECT i.id, i.title
FROM interviews i
INNER JOIN interview_keywords ik1
ON ik1.interview.id = i.id
AND ik.keyword_id = 39
AND ik1.sort = 1
INNER JOIN interview_keywords ik2
ON ik2.interview.id = i.id
AND ik2.keyword_id = 33
AND ik2.sort = 2
INNER JOIN interview_keywords ik3
ON ik3.interview.id = i.id
AND ik3.keyword_id = 51
AND ik3.sort = 3
INNER JOIN interview_keywords ik4
ON ik4.interview.id = i.id
AND ik4.keyword_id = 96
AND ik4.sort = 4
INNER JOIN interview_keywords ik5
ON ik5.interview.id = i.id
AND ik5.keyword_id = 97
AND ik5.sort = 5
WHERE i.cat_id = 1