I have 2 tables namely ItemList table and ItemChara table, having this kind of structure:
wherein, Item_Num of Item Chara is a foreign key of Item List table. Now I'm trying to JOIN these tables. With a given like these.
How can I JOIN these tables with those values to form something Like this
I'm trying to find out what is the simplest way to achieve this. I limit the colors in table Item Chara at maximum of 2 colors per Item so it won't exceed 2 colors per item. I want to make another column like Color1 and Color2 to get each color in each item. If it happens that the item doesn't have a color to pair up with, it would just left blank, or null maybe.
Sorry but I'm not sure what to call the thing that I want to do but I know the output that I want to have, so the question title might be irrelevant. I'll change it as soon as I found out.
One way to do this is to use the row_number() window function:
select
i.item_num, i.item_name,
max(case when rn = 1 then ic.chara_color end) color1,
max(case when rn = 2 then ic.chara_color end) color2
from itemlist i
join (
select
item_num, chara_color,
rn = row_number() over (partition by item_num order by chara_num)
from itemchara
) ic on i.item_num = ic.item_num
group by i.item_num, item_name;
Below code will give u the required result.
select A.item_num,A.Item_name,
max(Color_1) AS Color_1,
max(Color_2) As Color_2
from (
select il.item_num,il.Item_name,
(case when ic.chara_num = 1 then ic.chara_color END) AS Color_1,
(case when ic.chara_num = 2 then ic.chara_color END) AS Color_2
from Item_List il inner join Item_Chara ic on il.Item_Num = ic.Item_Num
) A
group by item_num,Item_name
This code is not tested may be have some syntax erro which u need to check and sort it out. Let me know if still ur facing some issue.
Similar to other answers, but since I already made it I might post it anyway.
;with itemlist(itemId, itemName)
as
(
select 1,'Bag'
union ALL
select 2,'Pen'
union ALL
select 3,'Bike'
union ALL
select 4,'Shoes'
)
,itemchara(charaId, itemId, charaColor)
as
(
select 1, 1, 'Blue'
union all
select 2, 1, 'Red'
union all
select 3, 2, 'Black'
union all
select 4, 2, 'Blue'
union all
select 5, 3, 'Green'
union all
select 6, 4, 'Black'
)
,tmp
as
(
select i.itemName
,c.*
,row_number () over ( partition by c.itemId order by c.charaId ) as r
from itemlist i
join itemchara c
on i.itemId = c.itemId
)
select t1. itemId
,t1.itemName
,t1.charaColor
,t2.charaColor
from tmp t1
left join tmp t2
on t1.r+1 = t2.r
and t1.itemId = t2.itemId
where t1.r = 1
Related
I'm just 3 months of experience in MySQL. Here I'm trying to generate a report based on log and part table. When trying to join the "Part" table twice, the "Log" table Quantity gets doubled. Kindly let me know where I'm doing wrong.
Log Table
Part Table
Expected Report
Query Used
SELECT
report.*,
(SUM(report.quantity)) AS totalQuantity,
normalPart.price AS normalPrice,
premiumPart.price AS premiumPrice
FROM
log AS report
LEFT JOIN
(SELECT
*
FROM
part AS normalPart
WHERE
normalPart.type = 'normal'
GROUP BY normalPart.partNumber , normalPart.genId) AS normalPart ON report.partNumber = normalPart.partNumber
AND report.genId = normalPart.genId
AND normalPart.cat = report.fromCat
LEFT JOIN
(SELECT
*
FROM
part AS premiumPart
WHERE
premiumPart.type = 'premium'
GROUP BY premiumPart.partNumber , premiumPart.genId) AS premiumPart ON report.partNumber = premiumPart.partNumber
AND report.genId = premiumPart.genId
AND premiumPart.cat = report.toCat;
Query Result
This answers the original version of the question.
Aggregate before you join:
select l.*, p.normal_price, p.premium_price
from (select genid, partnumber, sum(quantity) as quantity
from log
group by genid, partnumber
) l left join
(select partnumber, genid,
max(case when type = 'normal' then price end) as normal_price,
max(case when type = 'premium' then price end) as premium_price
from part
group by partnumber, genid
) p
on p.partnumber = l.partnumber and p.genid = l.genid
I have a list of products identified by their SKUs. To simplify it, I just name them as A, B, C, D,... here. Each of these SKUs has been assigned by default an already existing GroupID, for simplicity I just number them as 1, 2, 3,... here.
The same GroupID would mean "These SKUs are equivalent, so it is ok to use/buy either one of them, as it makes no difference".
The problem is, some SKUs show up more than once as they come from a different buying source, but as they come from a different source, they have a different grouping.
The goal is therefore to consolidate the grouping and make sure they have the same groupings.
I already apologize if my illustration may not be super pretty, but I'm trying. Here's a small data table sample on how the raw data looks like (first line is the column names):
Source SKU GroupID
Seller1 A 1
Seller1 B 1
Seller1 C 1
Seller2 B 2
Seller2 D 2
Seller2 E 2
Seller3 A 3
Seller3 B 3
Seller4 F 4
Seller4 G 4
Seller4 H 4
The result should be like:
Source SKU GroupID
Seller1 A 1
Seller1 B 1
Seller1 C 1
Seller2 B 1
Seller2 D 1
Seller2 E 1
Seller3 A 1
Seller3 B 1
Seller4 F 4
Seller4 G 4
Seller4 H 4
Basically, if Any SKU in GroupID X is a subset of GroupID Y, then GroupID Y = GroupID X. But that should be applied on all GroupIDs, so it appears to be recursive.
I wish I could show the code that I tried already and I tried already for a few days, but I literally only managed to produce garbage.
In C# I'd know how to deal with this, but I can't seem to wrap my head around SQL as I am not that experienced and unfortunately I would need this in SQL.
I would be thankful for any kind of help, even if it's just a hint or direction you guys would suggest I should try. Thanks a lot!
You want a correspondence between groups, which you can calculate with a recursive CTE:
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select groupid1, min(groupid2) as overall_group
from cte
group by groupid1;
You can then join this back to the original table to get the "overall group":
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select t.*, g.overall_group
from t join
(select groupid1, min(groupid2) as overall_group
from cte
group by groupid1
) g
on t.groupid = g.groupid1;
Here is a db<>fiddle.
Note: Your sample data is rather "complete" so you don't need a recursive CTE for that particular data. However, I am guessing that your real groups have a bit less overlap in which case recursion is necessary.
First is to get all those sellers with subsets based on count. then filter using Group By
select table1.Source, SKU, case when table1.Source = t6.Source and t6.cnt > 1 then 1 else 2 end as GroupID
from table1
left join
(select t5.Source, count(t5.cnt) as cnt from (
select distinct t4.Source, t4.cnt from (
select t3.Source, count(t3.SKU) as cnt from (
select t1.Source, t1.SKU from table1 t1
left join table1 t2 on t2.SKU = t1.SKU ) t3
group by t3.Source, t3.SKU
order by t3.Source) t4) as t5
group by t5.Source) t6 on t6.Source = table1.Source
I searched a lot, but did not find a fitting answer, and after trying for several hours its time to ask someone who knows :)
Ok, This is the Query its about (all unneccessary content stripped):
SELECT
`id`,
`name`,
`details`,
`tour_type_id`,
`meeting_point_id`,
`start_date`,
`start_time`,
`end_date`,
`end_time`,
`max_guests`,
(SELECT
MAX(`level`)
FROM
`tour_notification`
WHERE
`model_id` = `tour`.`id`
AND `deactivated` != 1) `notification_level`,
(SELECT
MAX(`level`)
FROM
`guide_notification`
WHERE
(`tour1_id` = `tour`.`id`
OR `tour2_id` = `tour`.`id`)
AND `deactivated` != 1) `guide_notification_level`
FROM
`tour`
What I did not succeed in was to get the 2 MAX(level) in one:
Get the MAX from notification_level and guide_notification_level.
I do not need these values seperately, I just did not succeed getting in in one.
My best attempt was the following approach:
(SELECT
MAX(`level`)
FROM
(SELECT `level` FROM
`tour_notification`
WHERE
`model_id` = `tour`.`id`
AND `deactivated` != 1 UNION DISTINCT SELECT `level`
FROM
`guide_notification`
WHERE
(`tour1_id` = `tour`.`id`
OR `tour2_id` = `tour`.`id`)
AND `deactivated` != 1) as `notifications`) `notification_level`,
but here MySQL complained:
ERROR: Error 1054: Unknown column 'tour.id' in 'where clause'
If I add the tour table into the where clause of these subselects, it always gets the results for any items of tour table, not just the current one.
Anyone can push me in the right direction?
Thanks a lot!
The following might work for you. It provides three different ways of combining the levels into one column. Remove the ones you do not want.
SELECT
a.`id`,
a.`name`,
a.`details`,
a.`tour_type_id`,
a.`meeting_point_id`,
a.`start_date`,
a.`start_time`,
a.`end_date`,
a.`end_time`,
a.`max_guests`,
a.`tour_level`,
a.`guide_level`,
CONCAT(`tour_level`," ",`guide_level`) as `notification_level1`,
a.`tour_level` + a.`guide_level` as `notification_level2`,
GROUP_CONCAT(CONCAT(a.`tour_level`," ",a.`guide_level`) as `notification_level3`
FROM `tour` a
LEFT JOIN `tour_notification` b
ON a.`id` = b.`model_id` AND b.`deactivated` <> 1
LEFT JOIN `guide_notification` c
ON a.`id` = c.`tour2_id` AND c.`deactivated` <> 1
GROUP BY a.`id`
If you need the greatest value of two, you can use the GRATEST() function. But I think a UNION ALL subquery with LIMIT 1 would be more readable:
(
SELECT MAX(`level`) AS `max_level`
FROM `tour_notification`
WHERE `model_id` = `tour`.`id`
AND `deactivated` != 1
UNION ALL
SELECT MAX(`level`) AS `max_level`
FROM `guide_notification`
WHERE (`tour1_id` = `tour`.`id` OR `tour2_id` = `tour`.`id`)
AND `deactivated` != 1
ORDER BY max_level DESC
LIMIT 1
) AS `notification_level`
I have those queries
SELECT CA_id, item_id, item_Cant, item_desc FROM items WHERE CA_id = 135
SELECT CA_id, prov_name, unitval, totval FROM provprices WHERE CA_id = 135 AND prov_name = 'SITECH'
and I want to join this two results, just like:
item_id - item_Cant - item_desc - unitval - totval
I tried diferent forms but the max that i can get is:
(If you notice the result from second table is dublicated, should be like the second image )
SELECT items.item_id,items.item_Cant,items.item_desc,provprices.unitval,provprices.totval
FROM items,provprices
WHERE items.CA_id = provprices.CA_id
AND provprices.prov_name = 'SITECH'
AND items.CA_id = '135'
GROUP BY items.item_id
If i change to GROUP BY provprices.unitval the duplicated result now is the first one
I hope you can help me. Thanks
I don't understand so much, but try this,
How do you wanna calculate the unitval and the totval
select item_id, item_Cant, item_desc, AVG(unitval), sum(totval)
from (
SELECT CA_id, item_id, item_Cant, item_desc
FROM items
WHERE CA_id = 135
) A
inner join (
SELECT CA_id, prov_name, unitval, totval
FROM provprices
WHERE CA_id = 135 AND prov_name = 'SITECH'
) B ON A.CA_id=B.CA_id
GROUP BY item_id, item_Cant, item_desc
I can't understand why this doesn't work:
select distinct a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
from #TempExportList a
join tblAnswers b
on a.QuestionID = b.QuestionID
where a.PaperID=#PaperID
order by (case when a.QuestionName='A' then 0
when a.QuestionName='B' then 1
else a.QuestionID
end)
I get the following error -
ORDER BY items must appear in the
select list if SELECT DISTINCT is
specified.
But this works fine:
select distinct a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
from #TempExportList a
join tblAnswers b
on a.QuestionID = b.QuestionID
where a.PaperID=#PaperID
order by a.QuestionID
The error message explains the problem perfectly.
In the first example the ORDER BY item -- CASE WHEN ... END -- doesn't appear in the SELECT list.
In the second example the ORDER BY item -- a.QuestionID -- does appear in the SELECT list.
To fix the first example you'll need to do something like this:
SELECT DISTINCT a.QuestionID, a.QuestionName, b.AnswerID, b.AnswerName,
CASE WHEN a.QuestionName = 'A' THEN 0
WHEN a.QuestionName = 'B' THEN 1
ELSE a.QuestionID
END
FROM #TempExportList AS a
JOIN tblAnswers AS b
ON a.QuestionID = b.QuestionID
WHERE a.PaperID = #PaperID
ORDER BY CASE WHEN a.QuestionName = 'A' THEN 0
WHEN a.QuestionName = 'B' THEN 1
ELSE a.QuestionID
END
You can get around this with a CTE
;WITH T AS
(
SELECT DISTINCT a.QuestionID,a.QuestionName,b.AnswerID,b.AnswerName
FROM #TempExportList a
JOIN tblAnswers b
ON a.QuestionID = b.QuestionID
WHERE a.PaperID=#PaperID
)
SELECT *
FROM T
ORDER BY
CASE
WHEN QuestionName='A'
THEN 0
WHEN QuestionName='B'
THEN 1
ELSE QuestionID
END
I would have thought the message self explanitory.
You have selected a distinct on a.QuestionID,a.QuestionName,b.AnswerID and b.AnswerName. Therefore, there could be rows of data with the same respective values for each of these fields, but a different one for your case statement.
Consider this
a.QuestionID a.QuestionName b.AnswerID b.AnswerName [case statement]
1 'One' 2 'Two' 0
1 'One' 2 'Two' 1
How does the query know which value in the last column to use in the order? Is it 0? It is 1? Quite simply, it can't determine, so it can't use it, hence the error.
The second example is fine, because a.QuestionID does appear in the SELECT list, and the query can happily apply the ordering.