sql query with sum or column - mysql

I have a table color_balls entries as below
=====================================================
Name Red_Ball Green_Ball Yellow_Ball
=====================================================
John 27 56 66
Mathew 37 45 15
=====================================================
I want to write a sql or mysql query to get the output as below.
=====================================
Color_of_Balls No_of_balls
=====================================
Red_Ball 64
Green_Ball 101
Yellow_Ball 81
=====================================

This type of query is called UNPIVOT, which unfortunately isn't natively supported by MySQL. However, you can simulate this using UNION:
SELECT 'Red_Ball' AS Color_of_Balls, SUM(Red_Ball) as No_of_Balls
FROM color_balls
UNION ALL
SELECT 'Green_Ball', SUM(Green_Ball)
FROM color_balls
UNION ALL
SELECT 'Yellow_Ball', SUM(Yellow_Ball)
FROM color_balls
Oracle10g doesn't support this natively either, although there is this workaround.

This should work in both Oracle and MySQL:
SELECT b.Color_of_Balls
, CASE b.Color_of_Balls
WHEN 'Red_Ball' THEN d.sum_red_ball
WHEN 'Green_Ball' THEN d.sum_green_ball
WHEN 'Yellow_Ball' THEN d.sum_yellow_ball
END AS No_of_balls
FROM ( SELECT 'Red_Ball' AS Color_of_Balls FROM DUAL
UNION ALL SELECT 'Green_Ball' FROM DUAL
UNION ALL SELECT 'Yellow_Ball' FROM DUAL
) b
CROSS
JOIN ( SELECT SUM(c.Red_Ball) AS sum_red_ball
, SUM(c.Green_Ball) AS sum_green_ball
, SUM(c.Yellow_Ball) AS sum_yellow_ball
FROM color_balls c
) d
ORDER
BY CASE b.Color_of_Balls
WHEN 'Red_Ball' THEN 1
WHEN 'Green_Ball' THEN 2
WHEN 'Yellow_Ball' THEN 3
END
Note that this approach requires only one pass through the color_balls table, rather than three separate passes through the table (or more, depending on how many rows you need returned.)

Related

SQL to club records in sequence

I have data in MySQL table, my data looks like
Key, value
A 1
A 2
A 3
A 6
A 7
A 8
A 9
B 1
B 2
and I want to group it based on the continuous sequence. Data is sorted in the table.
Key, min, max
A 1 3
A 6 9
B 1 2
I tried googling it but could find any solution to it. Can someone please help me with this.
This is way easier with a modern DBMS that support window functions, but you can find the upper bounds by checking that there is no successor. In the same way you can find the lower bounds via absence of a predecessor. By combining the lowest upper bound for each lower bound we get the intervals.
select low.keyx, low.valx, min(high.valx)
from (
select t1.keyx, t1.valx from t t1
where not exists (
select 1 from t t2
where t1.keyx = t2.keyx
and t1.valx = t2.valx + 1
)
) as low
join (
select t3.keyx, t3.valx from t t3
where not exists (
select 1 from t t4
where t3.keyx = t4.keyx
and t3.valx = t4.valx - 1
)
) as high
on low.keyx = high.keyx
and low.valx <= high.valx
group by low.keyx, low.valx;
I changed your identifiers since value is a reserved world.
Using a window function is way more compact and efficient. If at all possible, consider upgrading to MySQL 8+, it is superior to 5.7 in so many aspects.
We can create a group by looking at the difference between valx and an enumeration of the vals, if there is a gap the difference increases. Then, we simply pick min and max for each group:
select keyx, min(valx), max(valx)
from (
select keyx, valx
, valx - row_number() over (partition by keyx order by valx) as grp
from t
) as tt
group by keyx, grp;
Fiddle

Reorganizing mysql aggregate row into single piece rows

Consider the following mysql table:
ID WeightS AmountS WeightM AmountM WeightL AmountL Someothercolumnshere
1 6 3 10 2 18 2 ...
I need to reorganize this data into a pivot-friendly table, where each piece in the amount columns should be one result row. E.g. from the first two columns, WeightS and AmountS, the SELECT should produce 3 result rows, each having a weight of 2 kgs (=6 kgs total). So the full result table should be like this:
Weight Someothercolumnshere
2 ...
2 ...
2 ...
5 ...
5 ...
9 ...
9 ...
I don't even know if there's a SQL syntax which is able to do this kind of operation? I've never had a request like this before. Worst case scenario, I have to do it in php instead, but I think MYSQL is a lot more fun :p
I've built the schema on sqlfiddle, but I'm afraid that's all I've got.
You need a Tally table for the task like this. Create as much rows as needed in it.
Create table Tally(`N` int);
insert into Tally( `N`) values(1),(2),(3),(4),(5);
Then
(select `ID`, `WeightS`/`AmountS`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountS` >= Tally.`N`
)
UNION ALL
(select `ID`, `WeightL`/`AmountL`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountL` >= Tally.`N`
)
UNION ALL
(select `ID`, `WeightM`/`AmountM`, `Someothercolumnshere`
from Catches
join Tally on Catches.`AmountM` >= Tally.`N`
)

Unable to apply WHERE/AND on MySQL table with 2 columns on MAMP

I thought I had a very simple query to perform, but I can't seem to make it work.
I have this table with 2 columns:
version_id trim_id
1 15
1 25
1 28
1 30
1 35
2 12
2 25
2 33
2 48
3 11
3 25
3 30
3 32
I am trying to get any version-id's that have say a sub-set of trim_id's. Let's say all version_id's that have trim_id's 25 and 30. My obvious attempt was :
SELECT * FROM table WHERE trim_id=25 AND trim_id=30
I was expecting to have version_id 1 and 3 as a result, but instead I get nothing.
I am working with the latest version of MAMP, which has some odd behavior, like in this case it just tells me its 'LOADING' and never gives me an error message or something. But that's normally the case when there is no data to return.
This is InnoDB, if that helps.
Thanks for your input.
Your query does not work because you are using AND and the trim_id cannot have two different values at the same time, so you need to apply Relational Division to get the result.
You will need to use something similar to the following:
SELECT version_id
FROM yourtable
WHERE trim_id in (25, 30)
group by version_id
having count(distinct trim_id) = 2
See SQL Fiddle with Demo.
This will return the version_id values that have both 25 and 30. Then if you wanted to include additional columns in the final result, you can expand the query to:
select t1.version_id, t1.trim_id
from yourtable t1
where exists (SELECT t2.version_id
FROM yourtable t2
WHERE t2.trim_id in (25, 30)
and t1.version_id = t2.version_id
group by t2.version_id
having count(distinct t2.trim_id) = 2);
See SQL Fiddle with Demo
SELECT *
FROM table
WHERE trim_id IN(25,30)

Oracle/MYSQL: Sort records from a select query on a column that contains alphanumeric values

I know that this question has been asked in various forms but my requirement happens to be a bit different.
Suppose I have a table that contains data as follows:
ID NAME VALUE
-----------------------------
1 ABC-2-2 X
2 PQRS-1-3 Y
3 ABC-3-2 Z
4 PQRS-1-4 A
5 PQRS-3-4 B
6 MNO-2-1 C
7 AAA-1 D
8 BBB-2 E
9 CCC-3 F
Now, the output that I'm expecting should look something like this:
ID NAME VALUE
-----------------------------
7 AAA-1 D
2 PQRS-1-3 Y
4 PQRS-1-4 A
8 BBB-2 E
6 MNO-2-1 C
1 ABC-2-2 X
9 CCC-3 F
3 ABC-3-2 Z
5 PQRS-3-4 B
Note that this is not a direct alpha-numeric sort. Instead, the value before the first "-" is ignored and the fields are sorted on what is after the first "-" in the name.
I'm not very familiar with PL/SQL and any kind of help on this would be appreciated.
Thanks.
PS: Note that this should work on both Oracle and MySQL.
For your example this would suffice (Oracle syntax):
ORDER BY SUBSTR(name,4)
If the number of characters before the first hyphen can vary, you can do this (again Oracle syntax):
ORDER BY SUBSTR(name,INSTR(name,'-')+1)
However that won't work if you have codes like:
AAA-10-1
AAA-8-1
AAA-9-1
and expect AAA-10-1 to appear after AAA-9-1. Then you will need to parse it further:
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0')
(NB I have used LPAD(x,10,'0') to turn a value like '1' into '0000000001' and so on, rather than use TO_NUMBER since this could fail if there are any non-numerics in your data.)
Example:
with data as
(
select 'AAA-1' name from dual
union all
select 'PQR-1-4' name from dual
union all
select 'PQR-1-3' name from dual
union all
select 'AAA-10-10' name from dual
union all
select 'AAA-10-1' name from dual
union all
select 'AAA-9-10' name from dual
union all
select 'AAA-9-1' name from dual
)
select *
from data
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0');
Output:
NAME
---------
PQR-1-3
PQR-1-4
AAA-9-1
AAA-9-10
AAA-10-1
AAA-10-10
AAA-1
And if AAA-1 should come first:
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name||'-','-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name||'-','-',1,2)+1),10,'0') nulls first
Not sure about mysql syntax, but you can do this in oracle:
select * from <your_table>
order by substr(name, 5)
in mssql the syntax of finding your problem is :
select * from mytable order by substring(name,PATINDEX('%-%',name)+1,len(name)-PATINDEX('%-%',name))
SqlFiddle

MySQL Table UNION ISSUE

I'm trying to unite two tables in MySQL, the query I'm using is:
SELECT qa_invoicesitems.item_code, qa_invoicesitems.item_unitprice, qa_invoicesitems.item_subtotal, qa_invoicesitems.item_discount,
qa_invoicesitems.item_total
FROM qa_invoicesitems
RIGHT JOIN qa_invoicesitems_returnlog USING (item_code)
WHERE invoice_code = 17
UNION
SELECT qa_invoicesitems_returnlog.item_code, qa_invoicesitems_returnlog.item_unitprice, qa_invoicesitems_returnlog.item_subtotal,
qa_invoicesitems_returnlog.item_discount, qa_invoicesitems_returnlog.item_total
FROM qa_invoicesitems_returnlog
LEFT JOIN qa_invoicesitems USING (item_code)
WHERE returnlog_code = 9
But I can not behold the desired result.
A graphical example ..
Anyone have any idea how I can get this result?
NOTE: qa_invoicesitems_returnlog Replaces the data.
The codes: 1234, 1585, 23 are taken from (qa_invoicesitems_returnlog), because they exist in both tables, the rest are simply displayed.
Based upon your comments & your image, I'm going to say you want:
all the rows in table 2 where qa_invoicesitems_returnlog = 9
all the rows in table 1 where invoice_code = 17, except for those rows w/ item_id's that are already present in the output from table 2.
So, writing that out as a union, give you:
SELECT qa_invoicesitems_returnlog.item_code as item_code,
qa_invoicesitems_returnlog.item_unitprice as item_unitprice,
qa_invoicesitems_returnlog.item_subtotal as item_subtotal,
qa_invoicesitems_returnlog.item_discount as item_discount,
qa_invoicesitems_returnlog.item_total as item_total
FROM qa_invoicesitems_returnlog
WHERE qa_invoicesitems_returnlog.returnlog_code = 9
UNION
SELECT qa_invoicesitems.item_code as item_code,
qa_invoicesitems.item_unitprice as item_unitprice,
qa_invoicesitems.item_subtotal as item_subtotal,
qa_invoicesitems.item_discount as item_discount,
qa_invoicesitems.item_total as item_total
FROM qa_invoicesitems
WHERE qa_invoicesitems.invoice_code = 17
AND NOT EXISTS (SELECT * FROM qa_invoicesitems_returnlog qir2
WHERE qir2.returnlog_code = 9
and qir2.item_code = qa_invoicesitems.item_code)
The key is the NOT EXISTS clause that excludes from the results from table 1 (qa_invoiceitems) that are already present in the output from table 2 and have a matching item_code.
Why are you using a UNION? I think the following is equivalent to your query:
SELECT qa_invoicesitems.item_code, qa_invoicesitems.item_unitprice,
qa_invoicesitems.item_subtotal, qa_invoicesitems.item_discount,
qa_invoicesitems.item_total
FROM qa_invoicesitems RIGHT JOIN
qa_invoicesitems_returnlog
USING (item_code)
WHERE invoice_code = 15 or returnlogcode = 8
The LEFT and RIGHT joins are doing the same thing because the tables are reversed.