MYSQL GROUP BY clause adding a non GROUP BY column - mysql

I have a table in MySQL and I want to do some group by operation. So here is my table
The expected result should be the sum of prices group by bag_no but the product_id should be the mainproduct='Y'. So the result should be like this
I can do the following
SELECT bag_no, sum(price) AS total_price
FROM myTable
GROUP BY bag_no
But this will not allow me to add product_id in the table which I also want. How can we do that?

One canonical way to do this involves joining to a subquery which finds the sums:
SELECT
t1.bag_no,
t1.product_id,
t2.total_price
FROM myTable t1
INNER JOIN
(
SELECT bag_no, SUM(price) AS total_price
FROM myTable
GROUP BY bag_no
) t2
ON t1.bag_no = t2.bag_no
WHERE
t1.mainproduct = 'Y';
With MySQL 8+, which supports analytic functions, we can slightly simplify the above query:
WITH cte AS (
SELECT
t1.bag_no,
t1.product_id,
SUM(price) OVER (PARTITION BY t1.bag_no) total_price,
t1.mainproduct
FROM myTable t1
)
SELECT bag_no, product_id, total_price
FROM cte
WHERE mainproduct = 'Y';

Related

How to perform calculations on queries in mysql that return multiple values

First query:
SELECT COUNT(sales.ucid) AS totalOutcomes
FROM sales
group by date(sales.saleDate)
Second query:
SELECT COUNT(*) AS joinedOutcomes
FROM sales
JOIN calls
ON sales.ucid = calls.call_id
group by date(sales.saleDate)
I now want to use the output from the second query and divide that by the output from the first query.
Can someone please help with this? Thanks!
Join the two queries.
SELECT t1.date, joinedOutcomes/totalOutcomes
FROM (
SELECT date(sales.saleDate) AS date, COUNT(sales.ucid) AS totalOutcomes
FROM sales
GROUP BY date
) AS t1
JOIN (
SELECT date(sales.saleDate) AS date, COUNT(*) AS joinedOutcomes
FROM sales
JOIN calls ON sales.ucid = calls.call_id
group by date
) AS t2 ON t1.date = t2.date

Filter MYSQL table for with maximum dates

I would like to filter my table and select all the lines where the date is the latest date in the column called 'date'
If possible I would like to use the 'where' function.
Note I have many rows with the same date. e.g I have a table with all days sales by product, but I want to see only the latest days sales.
You can use this query to get the whole list of records where date is the latest one:
SELECT *
FROM `table`
WHERE date=(SELECT MAX(date)
FROM `table`)
You can use a subquery:
select t.*
from t
where date = (select max(t2.date) from t t2);
If you wanted the latest day per product, then you would use a correlated subquery.
select t.*
from t
where date = (select max(t2.date) from t t2 where t2.product = t.product);
One option would be to use exists logic:
SELECT *
FROM yourTable t1
WHERE NOT EXISTS (SELECT 1 FROM yourTable t2 WHERE t2.date > t1.date);
On MySQL 8+, I like using RANK here:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY date DESC) rnk
FROM yourTable
)
SELECT *
FROM cte
WHERE rnk = 1;
You could also use Gordon's subquery approach for a third option.

Missing closing parenthesis using DENSE_RANK() MySQL

I am not sure where my syntax is wrong here. I need to display the top vendors based on invoice_total
select *
from (
select vendor_id, invoice_total,
dense_rank () over(partition by vendor_id order by invoice_total asc)
as ranking
from invoices) a1
MySQL only supports dense_rank() in version 8+. You can always use a correlated subquery:
select i.*
from invoices i
where i.invoice_total = (select max(i2.invoice_total)
from invoices i2
where i2.vendor_id = i.vendor_id
);
This assumes that "top vendors" refers to the largest totals, which is the opposite of your SQL.
There are other ways to express this. I also like using tuples in MySQL:
select i.*
from invoices i
where (i.vendor_id, i.invoice_total) in
(select i2.vendor_id, max(i2.invoice_total)
from invoices i2
group by i2.vendor_id
);
Add where a1.ranking = 1 for outer part of the SQL :
select *
from (
select vendor_id, invoice_total,
dense_rank () over(partition by vendor_id order by invoice_total asc)
as ranking
from invoices) a1
where a1.ranking = 1;

How to select * from table when group by?

select
OrderNo,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
from
tbl_Assign
group by
OrderNo
I want to select * from table also group by from table. How to do it?
To group by on all columns with a sum you cannot use *, you have to list all of the columns out and every column that isn't a function like Sum must be included in the group by.
So if you have other fields in your database such as OrderName, OrderedBy you can perform a group by like this:
Select
OrderNo,
OrderName,
OrderBy,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
From
tbl_Assign
Group By
OrderNo, OrderName, OrderBy
The following will create one row for every row in the tbl_Assign.
Each row will also show the summary information for the order.
This might not be what you need, but it's useful to understand it anyway.
SELECT T1.*, T2.*
FROM
( select * FROM tbl_Assign ) AS T1
LEFT JOIN ( select
OrderNo,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
from
tbl_Assign
group by
OrderNo
) AS T2
ON T1.OrderNo = T2.OrderNo
Harvey

Diff value last two record by datetime

I have table with id, item_id, value (int), run (datetime) and i need select value diff betwen last two run per *item_id*.
SELECT item_id, ABS(value1 - value2) AS diff
FROM ( SELECT h.item_id, h.value AS value1, h2.value AS value2
FROM ( SELECT id, item_id, value
FROM table_name
GROUP BY item_id
ORDER BY run DESC) AS h
INNER JOIN ( SELECT id, item_id, value
FROM table_name
ORDER BY run DESC) AS h2
ON h.item_id = h2.item_id AND h.id != h2.id
GROUP BY item_id) AS h3
I believe this should do the trick for you. Just replace table_name to correct name.
Explanation:
Basicly I join the table with itself in a run DESC order, JOIN them based on item_id but also on id. Then I GROUP BY them again to remove potential 3rd and so on cases. Lastly I calculate the difference between them through ABS(value1 - value2).
SELECT t2.id, t2.item_id, (t2.value- t1.value) valueDiff, t2.run
FROM ( table_name AS t1
INNER JOIN
table_name AS t2
ON t1.run = (SELECT MAX(run) FROM table_name where run < t2.run)
and t1.item_id = t2.item_id)
This is assuming you want the diff between a record and the record with the previous run