I have a table called code_status:
Code Message
1 "Start"
2 "In process"
3 "Finish"
And another table called history
ID Code Name time_date
1 2 Jon 1/2/15
31 1 Abby 2/1/15
12 3 Sara 3/3/15
31 2 Abby 2/3/15
31 3 Abby 2/5/15
8 2 Max 1/22/15
I want to create an history_view with the following schema:
history_view (id, name, start_date, process_date, finish_date)
If the date is not given, it would just be NULL
So it would look like
ID Name start_date process_date finish_date
31 Abby 2/1/15 2/3/15 2/5/15
1 Jon NULL 1/2/15 NULL
... etc
So i started off by doing :
CREATE VIEW history_view
AS SELECT h.id, h.name,
(CASE WHEN h.code = 1 THEN time_date) AS start_date,
(CASE when h.code = 2 THEN time_date) AS process_date,
(CASE when h.code = 3 THEN time_date) AS finish_date
FROM history h;
I would get a result like the following below though:
ID Name start_date process_date finish_date
31 Abby 2/1/15 NULL NULL
31 Abby NULL 2/3/15 NULL
31 Abby NULL NULL 2/5/15
... ETC
Is there any way to consolidate the rows together ?
When you say consolidate you're referring to aggregation, you can use an aggregate function, such as min:
CREATE VIEW history_view
AS SELECT h.id, h.name,
min(CASE WHEN h.code = 1 THEN time_date) AS start_date,
min(CASE when h.code = 2 THEN time_date) AS process_date,
min(CASE when h.code = 3 THEN time_date) AS finish_date
FROM history h
group by h.id, h.name;
Related
I need to generate average sales per Title between year 2019 to 2021. There are 2 input tables:
Title Table
Title_id Title_type Price_per
1 tv 10
2 book 50
3 cd 20
Transactions table(trans)
tran_id Title_id Qty year
1 3 2 2019
2 1 1 2019
3 3 5 2020
4 3 3 2020
5 1 10 2021
The expected result should generate below columns:
Title_id|Avg_sales_2019|Avg_sales_2020|Avg_sales_2021
title_id avg_sales_2019 avg_sales_2020 avg_sales_2021
1 10.0 NULL 100.0
3 40.0 80.0 NULL
I used below query, but it does not generate the expected output
select a.title_id,
case when a.year=2019 then avg end as Avg_sales_2019,
case when a.year=2020 then avg end as Avg_sales_2020,
case when a.year=2021 then avg end as Avg_sales_2021
from (Select t.title_id, x.year, AVG(t.Price_per*x.Qty) as avg
from title t join trans x on t.title_id=x.title_id
group by t.title_id,x.year) a;
title_id avg_sales_2019 avg_sales_2020 avg_sales_2021
1 10.0 NULL NULL
1 NULL NULL 100.0
3 40.0 NULL NULL
3 NULL 80.0 NULL
How to combine the rows for a particular title_id to get the expected result
Note: I am running the query in Hive
Use conditional aggregation:
SELECT
t.title_id,
AVG(CASE WHEN x.year = 2019
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2019,
AVG(CASE WHEN x.year = 2020
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2020,
AVG(CASE WHEN x.year = 2021
THEN t.Price_per * x.Qty ELSE 0 END) AS avg_sales_2021
FROM title t
LEFT JOIN trans x
ON x.title_id = t.title_id
GROUP BY
t.title_id
ORDER BY
t.title_id;
I need to merge multiple rows(2 rows in 1 base on conditions) in my table in one, base on:
same custid and same appdate and price = paid
and have the desire output.
My data now:
tbla
appid custid appdate price paid
1 1 10/10/20 20 null
2 2 10/10/20 10 null
3 1 11/10/20 30 null
4 3 12/10/20 20 null
5 1 13/10/20 20 null
6 1 10/10/20 null 20
7 2 11/10/20 null 10
8 1 11/10/20 null 20
9 3 12/10/20 null 20
10 1 13/10/20 null 20
Derire output:
tblb
appid custid appdate price paid
1 1 10/10/20 20 20 => same custid, same appdate, price=paid
2 2 10/10/20 10 null
3 1 11/10/20 30 null
4 3 12/10/20 20 20 => same custid, same appdate, price=paid
5 1 13/10/20 20 20 => same custid, same appdate, price=paid
7 2 11/10/20 null 10
8 1 11/10/20 null 20
Don't bother with appid.I am going to rebuild appid in the end, by creating a new fresh table.
You seem to want aggregation with a twist:
select min(appid) as appid, custid, appdate,
max(price) as price, max(paid) as paid
from tbla
group by custid, appdate, coalesce(price, paid);
The twist is treating the price/paid as a single column.
Here is a db<>fiddle.
Note that in your sample data, one of paid or price is always NULL. If there are exceptions, then this code might not work. I would suggest that you ask a new question with appropriate sample data and desired results if that is the case.
It looks like simple aggregation does what you want:
select min(appid) as appid, custid, appdate, sum(price) as price, sum(paid) as paid
from mytable
group by custid, appdate
You can use a join with union:
with r as
(select t2.appid t2app, t1.appid, t1.custid, t1.appdate, t1.price, t2.paid from test t1 join test t2 on t1.custid = t2.custid and t1.appdate = t2.appdate and t1.price = t2.paid)
select r.appid, r.custid, r.appdate, r.price, r.paid from r
union
select * from test where not exists (select 1 from r where r.t2app = test.appid) and not exists (select 1 from r where r.appid = test.appid);
I'm trying to pull some SQL reports from an inventory system backend.
The table I'm trying to report on has an 'action' column (for tracking check in or out) and a 'timestamp' column.
I'm trying to reformat those into rows for each user/asset combo that has start and end times.
Sample data:
current:
row_id** user asset out_or_in timestamp
1 a 4 out 8:40
2 c 7 out 9:20
3 a 4 in 9:55
4 b 4 out 10:00
5 c 6 out 12:15
6 a 3 out 12:30
7 b 4 in 13:10
8 a 3 in 14:05
9 b 4 out 15:00
10 b 4 in 16:20
desired
row id** user asset out_time in_time
1 a 4 8:40 9:55
2 c 7 9:20
3 b 4 10:00 13:10
4 c 6 12:15
5 a 3 12:30 14:05
6 b 4 15:00 16:20
** not necessary, just included for table correctness
It gets more complicated by the fact that each user-asset pair can be repeated and would need to show as two rows.
Thoughts?
MySql 8.0 using row_number() window function to match out/in
select usr,asset
, max(case event when 'out' then ts end) out_time
, max(case event when 'in' then ts end) in_time
from (
select f.*,
-- first 'out' matches first 'in' and so on
row_number() over(partition by usr, asset, event order by ts) as grp
from foo f
) t
group by usr, asset, grp
order by out_time
Db fiddle
Here's a query for MySql 8 that makes use of a MIN OVER to calculate the in_time.
SELECT q.user, q.asset, q.out_time, q.in_time
FROM
(
SELECT t.user, t.asset, t.out_or_in,
CASE WHEN t.out_or_in = 'out' THEN t.`timestamp` END AS out_time,
MIN(CASE WHEN t.out_or_in = 'in' THEN t.`timestamp` END) OVER (PARTITION BY t.user, t.asset ORDER BY t.`timestamp` ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) AS in_time
FROM YourTable t
) q
WHERE q.out_time IS NOT NULL
ORDER BY q.out_time;
Test on db<>fiddle here
Result:
user asset out_time in_time
a 4 08:40:00 09:55:00
c 7 09:20:00
b 4 10:00:00 13:10:00
c 6 12:15:00
a 4 12:30:00 14:05:00
I am having trouble querying the correct date range. My query does not seem to consider the Where clause for post_date > (date provided).
SELECT `code`,
`description`,
SUM( IF( month = 3 && year = 2018, monthly_quantity_total, 0 ) ) AS monthlyqt,
SUM( IF( month = 3 && year = 2018, monthly_price_total, 0 ) ) AS monthlypt,
SUM( monthly_quantity_total ) AS yearlyqt,
SUM( monthly_price_total ) AS yearlypt
FROM (
SELECT `invoices_items`.`code`,
`invoices_items`.`description`,
SUM( invoices_items.discounted_price * invoices_items.quantity_supplied ) AS monthly_price_total,
SUM( invoices_items.quantity_supplied ) AS monthly_quantity_total,
YEAR( invoices_items.datetime_created ) AS year,
MONTH( invoices_items.datetime_created ) AS month
FROM `invoices_items`
JOIN `invoices` ON `invoices`.`id` = `invoices_items`.`invoice_id`
WHERE `invoices`.`is_finalised` = 1
AND `invoices`.`post_date` > 2018-02-28
AND `invoices_items`.`type` = 1
GROUP BY `year`, `month`, `invoices_items`.`code`
UNION ALL
SELECT `credit_notes_items`.`code`,
`credit_notes_items`.`description`,
SUM( credit_notes_items.discounted_price * credit_notes_items.quantity_supplied * -1 ) AS monthly_price_total,
SUM( credit_notes_items.quantity_supplied ) AS monthly_quantity_total,
YEAR( credit_notes_items.datetime_created ) AS year,
MONTH( credit_notes_items.datetime_created ) AS month
FROM `credit_notes_items`
JOIN `credit_notes` ON `credit_notes`.`id` = `credit_notes_items`.`credit_note_id`
WHERE `credit_notes`.`is_finalised` = 1
AND `credit_notes`.`post_date` > 2018-02-28
AND `credit_notes_items`.`type` = 1
GROUP BY `year`, `month`, `credit_notes_items`.`code`
) AS sub
GROUP BY code;
There are basically 4 tables being queried here. invoices, invoices_items, credit_notes and credit_notes_items.
table 1 - invoices
id post_date is_finalised
1 2018-01-01 1
2 2018-02-01 1
3 2018-03-01 1
table 2 - invoices_items
id invoice_id code description discounted_price quantity_total type
1 1 TEST-01 Test product 9.99 1 1
2 1 TEST-01 Test product 9.99 2 1
3 2 TEST-01 Test product 9.99 5 1
4 3 TEST-01 Test product 9.99 5 1
I have give some example rows above. From the table 1 and 2 above the desired result should be;
Desired Output
code description monthyqt monthlypt yearlyqt yearlypt
TEST-01 Test product 5 49.95 5 49.95
However the output I am receiving is as below;
Received Output
code description monthyqt monthlypt yearlyqt yearlypt
TEST-01 Test product 5 49.95 13 129.87
The query works as intended except for the date range I am trying to achieve by using the Where clause. You can see I am trying to filter out any row which are not matching invoices.post_date > 2018-02-28 (and also credit_notes.post_date > 2018-02-28).
I am not sure what I have done wrong here but any help will be much appreciated.
Thanks in advance.
I worked it out. Basically the variable which was parsing the date value needed to be encapsulated in single quotes.
e.g.
invoices.post_date > '2018-02-28'
It's always something this simple which throws you off.
I have a database like this:
custNum date purchase dayOfWeek
333 2001-01-01 23.23 1
333 2001-03-04 34.56 5
345 2008-02-02 22.55 3
345 2008-04-05 12.35 6
... ... ... ...
I'm trying to get the mode (most frequently occuring value) for the dayOfWeek column for each customer. Basically it would be the day of the week each customer shops the most on. Like:
custNum max(count(dayofweek(date)))
333 5
345 3
356 2
388 7
... ...
Any help would be great thanks.
select custNum, dayOfWeek
from tableName t
group by custNum, dayOfWeek
having dayOfWeek = (
select dayOfWeek
from tableName
where custNum = t.custNum
group by dayOfWeek
order by count(*) desc, dayOfWeek
limit 1
)