MySQL Conditional SELECT in SELECT - mysql

Table:
id price is_active
========================
1 20.99 0
2 10.99 1
3 30.99 0
4 15.99 1
5 35.99 1
I am trying to select COUNT of all rows that has is_active equals to 1, so I've used this simple query:
SELECT COUNT(*) FROM table WHERE is_active=1
But what if I want to also know how many rows have price:
less than 15
between 15 and 30
more than 30
I can write this:
SELECT COUNT(*) FROM table WHERE is_active=1 AND price < 15
SELECT COUNT(*) FROM table WHERE is_active=1 AND price > 15 AND price < 30
SELECT COUNT(*) FROM table WHERE is_active=1 AND price > 30
But can I do it in one simple query that returns something like this?
"Less than 15" | "Between 15 and 30" | "More than 30"
1 | 2 | 2

With conditional aggregation:
SELECT
SUM(price < 15) `Less than 15`,
SUM(price >= 15 AND price <= 30) `Between 15 and 30`,
SUM(price > 30) `More than 30`
FROM `table`
WHERE is_active=1
In MySql a boolean expression like price < 15 is evaluated as 0 for false or 1 for true.
See the demo.
Results:
| Less than 15 | Between 15 and 30 | More than 30 |
| ------------ | ----------------- | ------------ |
| 1 | 1 | 1 |

Because they are even intervals you could
SELECT
IF(price > 30, 30, price) div 15 as g,
count(*) as c
FROM `table`
WHERE is_active=1
GROUP BY g
Note this leaves 30 in the 'more than 30' category

Related

How to sort & group by sql query?

I have Data
id Date CatId itemid itemname price
1 10/5/2019 1 1 ABC 20
2 10/5/2019 1 2 XYZ 30
3 10/5/2019 2 1 ABC 20
4 10/5/2019 3 1 ABC 20
5 11/5/2019 1 2 XYZ 30
6 11/5/2019 2 1 ABC 20
7 11/5/2019 2 3 PQR 40
8 12/5/2019 3 1 ABC 20
9 12/5/2019 3 2 XYZ 30
10 12/5/2019 1 2 XYZ 30
11 12/5/2019 2 1 ABC 20
expected result data
date CatId toal
10/5/2019 1 50
10/5/2019 2 20
10/5/2019 3 20
11/5/2019 1 30
11/5/2019 2 60
12/5/2019 1 30
12/5/2019 2 20
12/5/2019 3 50
I want result order by date and after sum of price group by catid,
I have tried multiple query applied but get exact solution. I have spent so much time.
I have tried bellow queries
SELECT * FROM (SELECT * FROM `table` ORDER BY `date` DESC) as tbl
GROUP BY tbl.`catid`
SELECT *
FROM `table`
GROUP BY `date` ORDER BY `date` DESC
SELECT *
FROM (
SELECT * FROM `table`
ORDER BY `date` DESC
) AS sub
GROUP BY `catid` ORDER BY `date` DESC
the columns you can use in order by and group by can be different
You could use group by and sum directly
select date, catid, sum(price)
from my_table
group by date, catid
order by date, sum(price), catid

SQL Query get total value based on different unit price,quantity at different time

I have a transaction table that like this: quantity is the total quantity in stock based on different unit price. let's call it T
id | transaction_time | item | unit_price | quantity | subtotal
1 2012-5-15 A 1.00 15 15.00
2 2012-5-15 A 3.00 15 45.00
3 2012-5-15 B 1.00 10 10.00
4 2012-6-10 A 2.00 15 30.00
5 2012-6-15 A 2.00 10 20.00
I need to get the total value of each item in stock over time...however, same items are based on different unit price. The result for A for example is:
transaction_time | item | quantity | subtotal
2012-5-15 A 30 60.00
2012-6-10 A 45 90.00
2012-6-15 A 40 80.00
2012-5-15, we have 15 item A with price 1.00, 15 item A with price 3.00, so the total quantity is 30, subtotal is 15*1+15*3=60.
2012-6-10 we have 15 more item A with price 2, so the total quantity become 30+15=45, subtotal become 60+15*2=90
2012-6-15 we have 10 item A with price 2, so item A with price 2 goes down from 15 to 10. the total quantity become 40, and the subtotal goes down -2*5, which become 80.
I tried
select transaction_time,sum(quantity),sum(subtotal)
where id in(select max(id) from T group by unit_price,item)
group by item
having item=A
This only gives me the last line
2012-6-15 A 40 80.00
You need first to identify all possible unit_price values for the specific item:
SELECT DISTINCT unit_price
FROM t
WHERE item = 'A'
Output:
unit_price
----------
1
3
2
You also need to identify all possible transaction_times:
SELECT DISTINCT transaction_time
FROM t
WHERE item = 'A';
Output:
transaction_time
----------------
2012-05-15
2012-06-10
2012-06-15
Now perform a CROSS JOIN between the above two sets
SELECT *
FROM (
SELECT DISTINCT transaction_time
FROM t
WHERE item = 'A') AS times
CROSS JOIN (
SELECT DISTINCT unit_price
FROM t
WHERE item = 'A') AS up
ORDER BY times.transaction_time
to get:
transaction_time unit_price
----------------------------
2012-05-15 3
2012-05-15 2
2012-05-15 1
2012-06-10 3
2012-06-10 2
2012-06-10 1
2012-06-15 1
2012-06-15 3
2012-06-15 2
Now use the above and perform a correlated subquery to get unit_price per transaction_time from item 'A':
SELECT transaction_time, unit_price,
(SELECT quantity
FROM t
WHERE t.item = 'A'
AND t.unit_price = up.unit_price
AND t.transaction_time <= times.transaction_time
ORDER BY transaction_time DESC LIMIT 1) AS quantity
FROM (
SELECT DISTINCT transaction_time
FROM t
WHERE item = 'A') AS times
CROSS JOIN (
SELECT DISTINCT unit_price
FROM t
WHERE item = 'A') AS up
ORDER BY times.transaction_time
Output:
transaction_time unit_price quantity
----------------------------------------
15.05.2012 00:00:00 1 15
15.05.2012 00:00:00 3 15
15.05.2012 00:00:00 2 NULL
10.06.2012 00:00:00 1 15
10.06.2012 00:00:00 3 15
10.06.2012 00:00:00 2 15
15.06.2012 00:00:00 1 15
15.06.2012 00:00:00 3 15
15.06.2012 00:00:00 2 10
The final result is simply a matter of performing a GROUP BY on the above:
SELECT transaction_time,
'A' AS item,
SUM(quantity) AS quantity,
SUM(quantity*unit_price) AS subtotal
FROM (
SELECT transaction_time, unit_price,
(SELECT quantity
FROM t
WHERE t.item = 'A'
AND t.unit_price = up.unit_price
AND t.transaction_time <= times.transaction_time
ORDER BY transaction_time DESC LIMIT 1) AS quantity
FROM (
SELECT DISTINCT transaction_time
FROM t
WHERE item = 'A') AS times
CROSS JOIN (
SELECT DISTINCT unit_price
FROM t
WHERE item = 'A') AS up) AS x
GROUP BY transaction_time
Output:
transaction_time item quantity subtotal
----------------------------------------------
15.05.2012 A 30 60
10.06.2012 A 45 90
15.06.2012 A 40 80
Demo here
Following query(kind of complex, maybe slow, needs optimization) works, check DEMO
SELECT tr_sub.cur_tt, tr_sub.item, sum(tr.quantity), sum(tr.quantity*tr.unit_price)
FROM
(SELECT tr1.transaction_time as cur_tt, max(tr2.transaction_time) as prev_tt, tr1.item as item,
IF (tr1.unit_price=tr2.unit_price, tr1.unit_price, tr2.unit_price) as t_p
FROM transactions tr1 LEFT JOIN transactions tr2 ON
tr1.transaction_time>=tr2.transaction_time AND tr1.item=tr2.item
GROUP BY tr1.item, tr1.transaction_time, t_p
) as tr_sub INNER JOIN transactions tr ON
tr_sub.prev_tt=tr.transaction_time
AND tr_sub.item=tr.item
AND tr_sub.t_p=tr.unit_price
GROUP BY tr_sub.item, tr_sub.cur_tt
ORDER BY tr_sub.cur_tt, tr_sub.item

how to select the row where sum reach 1000?

id | amount
1 | 96
2 | 0.63
3 | 351.03
4 | 736
5 | 53
6 | 39
7 | 105
8 | 91
I want to get the row where sum(amount) reach 1000
please note only the row that trigger 1000
This query should do what (I think) you want:
select id, (select sum(amount)
from table1 t1
where t1.id <= table1.id) as total
from table1
having total >= 1000
limit 1
For your sample table, it gives
id total
4 1183.66

how can I group by elements from one table and group by it by 2 columns?

I have a table with a structure like this:
table_id | user_id | text | number_id | start_time
1 1 gdsgds 8 2015-10-11 07:14:44
2 2 vcxvc 8 2015-10-11 07:20:44
3 4 ewgs 8 2015-10-12 09:19:22
4 7 vvvcc 8 2015-10-13 18:12:23
etc.
I need to write a query that will return me the number of texts displayed each day on each number. So far I have the following query:
SELECT *
FROM
(
SELECT DATEDIFF(now(), start_time) AS days_ago,
COUNT(table_id) AS num_texts
FROM TABLE
GROUP BY DATE(start_time)
)
WHERE
(
days_ago <= 7
AND days_ago > 0
)
and this query returns me a table:
days_ago | num_texts
0 | 2
1 | 3
2 | 4
3 | 1
and that works almost fine, but I need to divide it by number_id too... How can I do it?
Add the column number_id to the select and group by in the subquery.
SELECT *
FROM
(
SELECT DATEDIFF(now(), start_time) AS days_ago,
number_id,
COUNT(table_id) AS num_texts
FROM TABLE
GROUP BY DATE(start_time), number_id
)
WHERE
days_ago <= 7
AND days_ago > 0

Showing today's current rank and yesterday's

I have a table with IDs, rank, chart_date, and pageviews. It's based on a cron job that is run nightly and compiles the number of pageviews for that ID.
For instance:
ID | RANK | PAGEVIEWS | CHART_DATE
5 1 100 2012-10-14
9 2 75 2012-10-14
13 3 25 2012-10-14
9 1 123 2012-10-13
5 2 74 2012-10-13
19 3 13 2012-10-13
So I'm grabbing today's chart based on 2012-10-14 and ranking the data by 1-3. But I also want to show the rank where the ID was on the previous date.
For instance, on 2012-10-14 ID 5 was ranked 1 but on 2012-10-13 it was ranked 2.
Can I do this with one query? Or do I have to loop thru the results based on today and do a query for each ID?
Can I do this with one query?
You can, but you need a JOIN between the table with today's date and the table with yesterday's date:
SELECT today.*, yesterday.rank
FROM yourtable AS today
JOIN yourtable AS yesterday
ON (today.id = yesterday.id
AND today.chart_date = date(now())
AND yesterday.chart_date = date(date_sub(now(), interval 1 day))
)
ORDER BY today.rank DESC;
You can even show the difference:
SELECT today.*, yesterday.rank AS yest, yesterday.rank-today.rank AS incr
FROM yourtable AS today
LEFT JOIN yourtable AS yesterday
ON (today.id = yesterday.id
AND today.chart_date = date(now())
AND yesterday.chart_date = date(date_sub(now(), interval 1 day))
)
ORDER BY today.rank DESC;
ID | RANK | PAGEVIEWS | CHART_DATE | YEST | INCR
5 1 100 2012-10-14 2 | 1
9 2 75 2012-10-14 1 | -1
13 3 25 2012-10-14 4 | 1
(LEFT JOIN ensures today's data is there even if yesterday's isn't).
Untested but something like this should work:
select today.id, today.rank, yesterday.rank
from mytable as today
left join mytable as yesterday on today.id = yesterday.id
where today.chart_date = 2012-10-14
order by pageviews desc limit 3