Difficult sql request - mysql

I've got some troubles with a sql request.
Here are my tables :
text :
id component_kind text
56 4 a
19 4 a
10 4 a
1 6 b
act :
id text_id detail_id detail_type
1 56 2 ItemGather
2 19 5 MonsterHunt
3 10 6 ItemUse
ItemGather :
id item_id count
2 1020 3
MonsterHunt :
id npc_id count
5 256 10
ItemUse :
id item_id count
6 3241 1
As you can see act.text_id is a foreign key of text.id and act.detail_id represents the id of one of the tables below act.
What I want to do is show something like this :
component_kind text gather_id gather_count use_id use_count hunt_id hunt_count
4 a 1020 3 3241 1 256 10
6 b 0 0 0 0 0 0
I don't know what to write in my request. Can any sql pro help me?

As mentioned in the comments above, simply outer-join the tables.
I use GROUP_CONCAT for the case that there is more than one match. In MySQL it would be allowed to simply select ig.item_id instead of group_concat(ig.item_id) which would give you a random ID in case there is more than one. It's up to you what you want to show in this case.
I use COALESCE to show 0 instead of NULL for sums when there are no matching records.
select
t.component_kind,
t.text,
group_concat(ig.item_id) as gather_ids,
coalesce(sum(ig.count),0) as gather_count,
group_concat(iu.item_id) as use_ids,
coalesce(sum(iu.count),0) as use_count,
group_concat(mh.npc_id) as hunt_is,
coalesce(sum(mh.count),0) as hunt_count
from text t
left outer join act a on a.text_id = t.id
left outer join itemgather ig on ig.id = a.detail_id and a.detail_type = 'ItemGather'
left outer join monsterhunt mh on mh.id = a.detail_id and a.detail_type = 'MonsterHunt'
left outer join itemuse iu on iu.id = a.detail_id and a.detail_type = 'ItemUse'
group by t.component_kind, t.text;
Here is the SQL fiddle: http://sqlfiddle.com/#!2/00cfb/10.

Related

join to most recent right hand record, but place NULL when right table doesn't have data

i am trying to build a view/query that hops across multiple joins showing one result row per left hand record, with the right hand record being the most recently-created record for that object in the table.
the end goal is to provide data to a front end application, but i need to be able to tell if there is no data in the right hand table while still displaying the data from the left hand table.
i don't know if i've worded that well; i'm a little out of my depth. maybe code will illustrate better than english. here are some tables to illustrate:
left hand table bill
id description extId
1 Some descr... SB 123
2 Another de... SB 124
3 Third desc... SB 125
join table tally_bill
id billId tallyId
1 2 1
2 2 2
3 3 3
4 3 4
note that there is no entry for billId = 1
right hand table tally
id countYes countNo created
1 4 0 2022-09-26 13:11:48
2 5 8 2022-09-26 14:50:24
3 10 11 2022-09-26 11:20:01
4 4 3 2022-09-26 13:41:25
my desired result looks something like this:
billId description extId countYes countNo
1 Some descr... SB 123 null null
2 Another de... SB 124 5 8
3 Third desc... SB 125 4 3
i need countYes and countNo to be the values from the most recently-created record in tally.
the query i've gotten so far is:
SELECT
bill.id, bill.description, bill.extId,
tally.id, tally.countYes, tally.countNo
FROM
bill
LEFT JOIN tally_bill
ON tally_bill.billId = bill.id
LEFT JOIN tally
ON tally.id = tb.tallyId
AND (
SELECT
MAX(tally.id)
FROM
tally_bill tb
WHERE
tb.billId = bill.id);
but this produces something to the effect of:
billId description extId id countYes countNo
2 Another de... SB 124 2 5 8
3 Third desc... SB 125 4 4 3
as you see the record billId = 1 is missing. i have made a few variations on this query moving the subquery around, trying group bys and partitions, etc., to no avail. i'm at the limit of my SQL-fu, so i would appreciate any help or enlightenment, please :)
i'm using MySQL 8.0.30 but if there is a need to change versions i'm open to it.
select id
,description
,extId
,countYes
,countNo
from (
select b.id
,b.description
,b.extId
,t.countYes
,t.countNo
,row_number() over(partition by b.id order by t.id desc) as rn
from bill b left join tally_bill tb on tb.billId = b.id left join tally t on t.id = tb.tallyId
) t
where rn = 1
id
description
extId
countYes
countNo
1
Some descr
SB 123
null
null
2
Another de
SB 124
5
8
3
Third desc
SB 125
9
4
Fiddle

Mysql join not showing all records

I am using Php with join, I have two tables ("services" and "service_detail"), I want to get all services
but want to know which service selected or notselected by vendor
Here is my services table strcture
id service_name image
1 Abc abc.jpg
2 xyz xyz.jpg
3 OPS ops.jpg
4 tys tys.jpg
5 byp byp.jpg
Here is my services_detail table strcutre
id vendor_id service_id price
1 101 1 50
2 101 2 70
3 101 3 80
4 101 4 30
5 102 1 70
6 102 2 40
...
I tried with following query but showing only selected services, but i want to get all services with parameter ( selected or notselected)
Where i am wrong ? Here is my query
SELECT sd.vendor_id, sd.service_id, sd.price, s.service_name, s.image
FROM services_detail sd
LEFT JOIN services s
ON sd.service_id = s.id
WHERE sd.vendor_id = '101'
Move your where clause to be AND in ON clause:
AND sd.vendor_id = '101'
And interchange tables in join to get all servcies
SELECT sd.vendor_id, sd.service_id, sd.price, s.service_name, s.image,
IF (sd.vendor_id is not null, 'Opted', 'Not opted') as status
FROM services s
LEFT JOIN services_detail sd
ON sd.service_id = s.id AND sd.vendor_id = '101';
In simple words, when there is a where clause including filters on table of Left Join then it will act like INNER JOIN not LEFT JOIN.

Mysql union, left join, group and count

Heres my query
SELECT
fsi_courier_assignment_print_master_listing.master_listing_id,
fsi_master_listing.transmittal_id,
fsi_transmittals.product_name,
fsi_transmittals.transmittal_id
FROM fsi_courier_assignment_print_master_listing
LEFT JOIN fsi_master_listing ON fsi_courier_assignment_print_master_listing.master_listing_id = fsi_master_listing.master_listing_id
LEFT JOIN fsi_transmittals ON fsi_master_listing.transmittal_id = fsi_transmittals.transmittal_id
WHERE dispatch_code_id=".$this->db->escape($dispatch_code_id)."
UNION ALL
SELECT
fsi_courier_assignment_print_master_listing_undelivered.master_listing_id,
fsi_master_listing.transmittal_id,
fsi_transmittals.product_name,
fsi_transmittals.transmittal_id
FROM fsi_courier_assignment_print_master_listing_undelivered
LEFT JOIN fsi_master_listing ON fsi_courier_assignment_print_master_listing_undelivered.master_listing_id = fsi_master_listing.master_listing_id
LEFT JOIN fsi_transmittals ON fsi_master_listing.transmittal_id = fsi_transmittals.transmittal_id
WHERE dispatch_code_id=".$this->db->escape($dispatch_code_id)."
fsi_courier_assignment_print_master_listing table
master_listing_id dispatch_code_id
2 2
5 2
36 2
37 2
134 2
135 2
136 2
137 2
138 2
139 2
140 2
fsi_courier_assignment_print_master_listing_undelivered table
master_listing_id dispatch_code_id
1 2
fsi_master_listing table
master_listing_id transmittal_id
1 1
2 1
5 2
36 2
37 2
134 3
135 3
136 3
137 3
138 3
139 3
140 3
fsi_transmittals table
transmittal_id product_name
1 Name 1
2 Name 2
3 Name 3
What Im trying to do is to get the combined result of product from fsi_courier_assignment_print_master_listing and fsi_courier_assignment_print_master_listing_undelivered where dispatch_code_id='2' and count them
My desire Output would be
Product Name Product Count
Name 1 2
Name 2 3
Name 3 7
Thanks in advance, hope somebody can help me to this..
Your query is fine, you just need to:
Add COUNT with GROUP BY product_name and put your query as a subquery.
The transmittal_id is specified two times in the two union queries, either remove one of them or give them different names (It might work fine in MySQL, but it is recommended not to do so).
So your query will be something like this:
SELECT
t.product_name,
COUNT(*) AS ProductCount
FROM
(
SELECT
ml.master_listing_id,
m.transmittal_id,
t.product_name
FROM fsi_courier_assignment_print_master_listing AS ml
LEFT JOIN fsi_master_listing AS m
ON ml.master_listing_id = m.master_listing_id
LEFT JOIN fsi_transmittals AS t
ON m.transmittal_id = t.transmittal_id
UNION ALL
SELECT
u.master_listing_id,
m.transmittal_id,
t.product_name
FROM fsi_courier_assignment_print_master_listing_undelivered as u
LEFT JOIN fsi_master_listing AS m
ON u.master_listing_id = m.master_listing_id
LEFT JOIN fsi_transmittals AS t
ON m.transmittal_id = t.transmittal_id
) AS t
GROUP BY t.product_name;
This will give you:

SQL join and count do net get it together

I'am a beginner in SQL and have some trouble with joining and counting at the same time.
First let me explain my two tables.
I have the following:
Table: AnalysePageview
id title session more
-----------------------------------------------------
1 a 10 0
2 b 20 1
3 c 30 1
4 d 40 1
5 e 50 1
6 f 60 0
Table: AnalyseEvent
id name session more
-----------------------------------------------------
1 a 10 0
2 b 10 1
3 c 10 1
4 d 20 1
and I would like to join this two and add a line like this:
New Table:
id name session counts (out off AnalyseEvent)
-----------------------------------------------------
1 a 10 3
2 b 20 1
3 c 30 0
4 d 40 0
5 e 50 0
6 f 60 0
I just tried this:
SELECT *,
COUNT( AnalyseEvent.session ) AS totalViews
FROM AnalysePageview
LEFT JOIN AnalyseEvent ON AnalysePageview.session = AnalyseEvent.session
thanks for any help in advance. (my be with a small beginner explanation)
You need a group by:
SELECT apv.id, apv.name, apv.session, COUNT( ae.session ) AS totalViews
FROM AnalysePageview apv LEFT JOIN
AnalyseEvent ae
ON apv.session = ae.session
GROUP BY apv.id, apv.name, apv.session;
I also added table aliases to make the query easier to write and to read.
You need to use group by. Something like:
select apw.id, apw.title, apw.session, count(1)
from AnalysePageview apw
left join AnalyseEvent ae
on apw.session = ae.session
group by apw.id, apw.title, apw.session

MySQL: Another max per group? Two tables

My database tracks sections users have completed:
Table 'users':
id user_id sections_id
//
4 46 1
5 46 2
6 46 4
7 46 5
//
Table 'sections':
id header_id name
1 1 1/3
2 1 2/3
3 1 3/3
4 2 1/3
5 2 2/3
6 2 3/3
The following query
SELECT a.sections_id
,b.header_id
FROM users a
JOIN sections b
ON a.sections_id = b.id
WHERE a.user_id = 46;
// a.user_id can be just user_id, but added for clarity
Gives me:
sections_id header_id
1 1
2 1
4 2
5 2
What I want is max section ID per header for a particular user, so that I know which section I need to serve the user:
sections_id header_id
2 1
5 2
I'm assuming this is a max per group problem, but I can't quite get my head around the solution. I could throw all the data into my PHP and parse out from there, but it seems I should be able to do it via the SQL. TIA!
This is a simple group by query:
SELECT s.header_id, max(u.sections_id)
FROM users u JOIN
sections s
ON u.sections_id = s.id
WHERE u.user_id = 46
group by s.header_id;
I also changed your aliases to be the initials of the table. This makes the query much easier to follow.
Edit: SQLFiddle Here: http://sqlfiddle.com/#!2/dbb5a/2
You could add a group by clause with a max() function
SELECT max(a.sections_id)
,b.header_id
FROM users a
JOIN sections b
ON a.sections_id = b.id
WHERE a.user_id = 46
GROUP BY header_id;