How to combine based on id in mysql - mysql

Please help to find out the result.How to a write a query to combine rows which has same id
id size sizeorder color colororder
1 M 1 null null
1 null null red 1
2 s 1 null null
2 Null null green 2
output should be
id size sizeorder color colororder
1 M 1 red 1
2 s 1 green 2

SELECT id,
MAX(size) AS size,
MAX(sizeorder) AS sizeorder,
MAX(color) AS color,
MAX(colororder) AS colororder
FROM yourTable
GROUP BY id
The rollup you are trying to do is similar to what happens in a pivot query. The "secret sauce" in the above query is that MySQL's MAX function ignores NULL values. This means that in your table only the non NULL values will be retained in each column, for each grouped id.

You have to join your tables and use case when to get the value which is not null:
select case when t1.size is null then t2.size else t1.size end as size,
case when t1.sizeorder is null then t2.sizeorder else t1.sizeorder end as sizeorder,
case when t1.color is null then t2.color else t1.color end as color
case when t1.colororder is null then t2.colororder else t1.colororder end as colororder
from <table> t1 join <table> t2 on t1.id = t2.id

Related

Derive fields from multiple sub-queries

I'm trying to use MySQL 8 to create a SELECT query that "creates" 5 new fields based on the results from 5 other queries, however, I'm struggling to work out how I get this to work.
Consider this scenario:
product_attributes
productid
attribute_name
attribute_value
1
Diameter
1mm
1
Width
2mm
1
Weight
1kg
1
Length
10mm
2
Diameter
12mm
2
Width
22mm
2
Weight
2kg
2
Length
20mm
Now consider that my "user input" wants the first Attribute to be "Width" and the second attribute to be "Weight", i.e. att1 = Width, att2=Weight, att3..... etc
I wish to construct a SELECT query that returns the following:
productid
att1
att2
1
2mm
1kg
2
22mm
2kg
I can get this to work with attribute 1, but I'm struggling to figure out how to make this work for attribute 2.
This is the query I have:
select `att1`,ATT_TABLE.productid FROM
(select `attribute_value` as att1, `productid` from `product_attributes` where attribute_name='Width') ATT_TABLE
JOIN products on ATT_TABLE.productid = products.productid
WHERE products.catid='12345'
Ignore the JOIN/WHERE - that is just some extra logic I need to grab a particular categories products, but I have included it in case it would break any answers received.
How do I modify the query to include another sub query SELECT statement to get my second attribute, or is there another method to achieve the same?
Kind of like this:
select `att1`,`att2`,ATT_TABLE.productid FROM
(select `attribute_value` as att1, `productid` from `product_attributes` where attribute_name='Width') ATT_TABLE
(select `attribute_value` as att2, `productid` from `product_attributes` where attribute_name='Weight') ATT_TABLE2
EDIT: An alternative suggestion by slashroot was to use CASE / GROUP BY.
select productid,
CASE
WHEN attribute_name ='Width' THEN attribute_value
END as att1,
CASE
WHEN attribute_name ='Weight' THEN attribute_value
END as att2
FROM product_attributes
WHERE productid='1'
)
However, this then returns multiple rows for the same productID and I'm struggling to figure out the GROUP BY statement.
This is the return from that statement:
productid
att1
att2
1
NULL
NULL
1
NULL
NULL
1
2mm
NULL
1
NULL
2kg
How do I get a group by to condense this down?
That was a good start you did in your EDIT above. But you were missing a couple steps.
Have a look at this query, it should return the desired results
SELECT productid,
MAX(CASE WHEN attribute_name = 'Width' THEN attribute_value ELSE NULL END) as att1,
MAX(CASE WHEN attribute_name = 'Weight' THEN attribute_value ELSE NULL END) as att2
FROM product_attributes
GROUP BY productid
Check the results from this DB FIDDLE

How to select data in mysql that all the joined table is not null on certain column

i have 2 table which is one to many
table order
order_id
order_date
1
2021/01/01
2
2021/01/02
3
2021/01/02
table detail order
detail_order_id
order_id
is_finished
1
1
null
2
1
2021/01/03
3
2
2021/01/04
4
2
2021/01/04
5
3
2021/01/05
6
3
2021/01/06
7
3
null
so i wanna data that have condition if some of the detail order rows is_finished column not null, so the status is gonna be not finish.
and if all the detail order rows is_finished column not contain any null value like id 2, so the status is finished
expected result
order_id
status
1
not finish
2
finished
3
not finish
It seems like you don't really need a join since table_detail_order already have order_id and you only want to check is_finished, you might just need a query on 1 table like:
SELECT order_id,
CASE WHEN SUM(is_finished IS NULL)=0
THEN 'Finished' ELSE 'Not finish' END AS 'Status'
FROM table_detail_order GROUP BY order_id;
Demo fiddle
Btw, is_finished IS NULL will return 1 (true) or 0 (false) so in a table it would look like:
order_id
is_finished
is_finished IS NULL
1
null
1
1
2021/01/03
0
2
2021/01/04
0
2
2021/01/04
0
3
2021/01/05
0
3
2021/01/06
0
3
null
1
Therefore SUM(is_finished IS NULL) with GROUP BY order_id; will do something like this:
order_id
SUM(is_finished IS NULL)
1
1+0=1
2
0+0=0
3
0+0+1=1
And that is why CASE WHEN SUM(is_finished IS NULL)=0 ... is considered as finished while otherwise as not finish.
we can solve the problem like this
left join order and order_detail,but has condition order_details.is_finished is null
so we get a result that the joined order_details's is_finished only null
in that case there is no order_details join with order 2
then we regard the result as a temp table,so when joined order_details has data then it is not finished
here is the example data,you can run query in it
select id,
case when order_id>0 then 'not finish' else 'finished' end as status
from (
select o.id,od.order_id from `order` as o
left join order_detail as od
on (o.id=od.order_id and od.is_finished is null)
group by o.id
) as _t
You can try this. This query uses a LEFT JOIN and COUNT. Where the first count counted the NULL values as ZERO and the second count counts all values, then compare the 2 counts, if the first and second count is equal to each other it means that the order details is finished, if not then not finish.
SELECT a.`order_id`,
IF(COUNT(IF(ISNULL(is_finished),0,1))=COUNT(is_finished), 'finished', 'not finish') AS `status` FROM `order` a
LEFT JOIN `detail_order` b ON a.`order_id`=b.`order_id`
GROUP BY a.`order_id` ;
RESULT*
order_id status
-------- ------------
1 not finish
2 finished
3 not finish

mysql query - where clause active only for the selection of a particular field

Let's say we have 2 tables:
t1: with columns t1.doc_id, ...
looks like this:
t1.doc_id
1
2
3
4
t2: with columns t2.from_doc_id, t2.to_doc_id, t2.flag, ...
looks like this
from_doc_id
to_doc_id
flag
1
100
null
1
101
null
2
100
null
3
8
set
I wanted to get a query result like this:
t1.doc_id
refs
1
100, 101
2
100
3
Basically, wherever flag is null, i want to collect all to_doc_id and concatenate them in a string if flag is not null. Like the first two results in the example above.
If flag is not null (like third row in t2 example), I still want to get the 3 in the query result, but the refs field should not contain 8.
with a query:
SELECT t1.doc_id, group_concat(t2.to_doc_id) AS refs
FROM t1
LEFT OUTER JOIN t2 ON t2.from_doc_id = t1.id
WHERE t2.flag is null
... i miss the last line entirely, I only get the first two lines from the expected result.
So I guess, what I want, is to use WHERE t2.flag is null in group_concat, but to ignore the t2.flag when I get the t1.doc_id values.
You can use CASE inside GROUP_CONCAT
SELECT from_doc_id
,group_concat(CASE WHEN flag IS NULL THEN to_doc_id ELSE '' END) AS refs
FROM yourtable t1
JOIN yourtable2 t2 ON t1.doc_id = t2.from_doc_id
GROUP BY from_doc_id
Demo on db<>fiddle

Join Distinct Id on non-distinct id (MySql)

I'm trying to join distinct ID's from a subquery in a FROM onto a table which has the same ID's, but non-distinct as they are repeated to create a whole entity. How can one do this? All of my tries are continuously amounting to single ID's in the non-distinct-id-table.
For example:
Table 1
ID val_string val_int val_datetime
1 null 3435 null
1 bla null null
1 null null 2013-08-27
2 null 428 null
2 blob null null
2 null null 2013-08-30
etc. etc. etc.
Virtual "v_table" from SubQuery
ID
1
2
Now, if I create the query along the lines of:
SELECT t.ID, t.val_string, t.val_int, t.val_datetime
FROM table1 AS t
JOIN (subquery) AS v_table
ON t.ID = v_table.ID
I get the result:
Result Table:
ID val_string val_int val_datetime
1 null 3436 null
2 null 428 null
What I'd like is to see the whole of Table 1 based on this example. (Actual query has some more parameters, but this is the issue I'm stuck on).
How would I go about making sure that I get everything from Table 1 where the ID's match the ID's from a virtual table?
SELECT t.ID, t.val_string, t.val_int, t.val_datetime
FROM table1 AS t
LEFT JOIN (subquery) AS v_table
ON t.ID = v_table.ID
Sample fiddle

MySQL merge amounts in a 2 rows

I'm looking to create a sql statement that will update a large set of data.
What I have is a table like
id, transid, amount, narative1, narative 2, total, active
1 1234 23.2 NULL NULL NULL 1
2 1234 120.33 NULL NULL NULL 1
3 1235 98.00 NULL NULL NULL 1
When there are two rows with the same transid I need to total them put the result in the total column of the first one with that transid and put the second amount in naritive2 of the first instance as well as make the second one inactive. It should ignore single rows for a transid.
The result of what I want to do should be:
id, transid, amount, narative1, narative 2, total, active
1 1234 23.2 NULL 120.33 143.53 1
2 1234 120.33 NULL NULL NULL 0
3 1235 98.00 NULL NULL NULL 1
I know a bit of a thong twister but..
Ideally I'd like to do this in just a MySQL statements. So I don't mind having to do multiple sql statements but I want to avoid connecting it to PHP etc. Its a very large set of data.
This will update only those transactions that have exactly 2 rows (not 1 and not 3 or more).
UPDATE mytable mtu
JOIN (
SELECT minid, maxid, mtmin.amount AS minamt, mtmax.amount AS maxamt
FROM (
SELECT MIN(id) AS minid, MAX(id) AS maxid
FROM mytable mti
GROUP BY
transid
HAVING COUNT(*) = 2
) mt
JOIN mytable mtmin
ON mtmin.id = minid
JOIN mytable mtmax
ON mtmax.id = maxid
) mts
ON id IN (minid, maxid)
SET narative2 = CASE id WHEN minid THEN minamt ELSE NULL END,
total = CASE id WHEN minid THEN minamt + maxamt ELSE NULL END,
active = (id = minid)