Postgresql how to select columns where it matches conditions? - sql

I have a table like this:
inventory_id | customer_id | max
--------------+-------------+---------------------
4497 | 1 | 2005-07-28 00:00:00
1449 | 1 | 2005-08-22 00:00:00
1440 | 1 | 2005-08-02 00:00:00
3232 | 1 | 2005-08-02 00:00:00
3418 | 2 | 2005-08-02 00:00:00
654 | 2 | 2005-08-02 00:00:00
3164 | 2 | 2005-08-21 00:00:00
2053 | 2 | 2005-07-27 00:00:00
I want to select rows where most recent date with corresponding columns, This is what I want to achieve:
inventory_id | customer_id | max
--------------+-------------+---------------------
1449 | 1 | 2005-08-22 00:00:00
3164 | 2 | 2005-08-21 00:00:00
I tried to use aggregate but I need inventory_id and customer_id appear at the same time.
Is there any method that could do this?

Use distinct on:
select distinct on (customer_id) t.*
from t
order by customer_id, max desc;
distinct on is a Postgres extension that returns on row per whatever is in the parentheses. This row is based on the order by -- the first one that appears in the sorted set.

SELECT inventory_id, customer_id, max FROM
(SELECT inventory_id, customer_id, max,
ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY max DESC) AS ROWNO
FROM inventory_table) AS A
WHERE ROWNO=1

Related

Find the first order of a supplier in a day using SQL

I am trying to write a query to return supplier ID (sup_id), order date and the order ID of the first order (based on earliest time).
+--------+--------+------------+--------+-----------------+
|orderid | sup_id | items | sales | order_ts |
+--------+--------+------------+--------+-----------------+
|1111132 | 3 | 1 | 27,0 | 24/04/17 13:00 |
|1111137 | 3 | 2 | 69,0 | 02/02/17 16:30 |
|1111147 | 1 | 1 | 87,0 | 25/04/17 08:25 |
|1111153 | 1 | 3 | 82,0 | 05/11/17 10:30 |
|1111155 | 2 | 1 | 29,0 | 03/07/17 02:30 |
|1111160 | 2 | 2 | 44,0 | 30/01/17 20:45 |
|....... | ... | ... | ... | ... ... |
+--------+--------+------------+--------+-----------------+
Output I am looking for:
+--------+--------+------------+
| sup_id | date | order_id |
+--------+--------+------------+
|....... | ... | ... |
+--------+--------+------------+
I tried using a subquery in the join clause as below but didn't know how to join it without having selected order_id.
SELECT sup_id, date(order_ts), order_id
FROM sales s
JOIN
(
SELECT sup_id, date(order_ts) as date, min(time(order_date))
FROM sales
GROUP BY merchant_id, date
) m
on ...
Kindly assist.
You can use not exists:
select *
from sales
where not exists (
-- find sales for same supplier, earlier date, same day
select *
from sales as older
where older.sup_id = sales.sup_id
and older.order_ts < sales.order_ts
and older.order_ts >= cast(sales.order_ts as date)
)
The query below might not be the fastest in the world, but it should give you all information you need.
select order_id, sup_id, items, sales, order_ts
from sales s
where order_ts <= (
select min(order_ts)
from sales m
where m.sup_id = s.sup_id
)
select sup_id, min(order_ts), min(order_id) from sales
where order_ts = '2022-15-03'
group by sup_id
Assumed orderid is an identity / auto increment column

Subtracting previous row value from current row

I'm doing an aggregation like this:
select
date,
product,
count(*) as cnt
from
t1
where
yyyy_mm_dd in ('2020-03-31', '2020-07-31', '2020-09-30', '2020-12-31')
group by
1,2
order by
product asc, date asc
This produces data which looks like this:
| date | product | cnt | difference |
|------------|---------|------|------------|
| 2020-03-31 | p1 | 100 | null |
| 2020-07-31 | p1 | 1000 | 900 |
| 2020-09-30 | p1 | 900 | -100 |
| 2020-12-31 | p1 | 1100 | 200 |
| 2020-03-31 | p2 | 200 | null |
| 2020-07-31 | p2 | 210 | 10 |
| ... | ... | ... | x |
But without the difference column. How could I make such a calculation? I could pivot the date column and subtract that way but maybe there's a better way
Was able to use lag with partition by and order by to get this to work:
select
date,
product,
count,
count - lag(count) over (partition by product order by date, product) as difference
from(
select
date,
product,
count(*) as count
from
t1
where
yyyy_mm_dd in ('2020-03-31', '2020-07-31', '2020-09-30', '2020-12-31')
group by
1,2
) t

How to calculate average of values without including the last value (sql)?

I have a table. I partition it by the id and want to calculate average of the values previous to the current, without including the current value. Here is a sample table:
+----+-------+------------+
| id | Value | Date |
+----+-------+------------+
| 1 | 51 | 2020-11-26 |
| 1 | 45 | 2020-11-25 |
| 1 | 47 | 2020-11-24 |
| 2 | 32 | 2020-11-26 |
| 2 | 51 | 2020-11-25 |
| 2 | 45 | 2020-11-24 |
| 3 | 47 | 2020-11-26 |
| 3 | 32 | 2020-11-25 |
| 3 | 35 | 2020-11-24 |
+----+-------+------------+
In this case, it means calculating the average of values for dates BEFORE 2020-11-26. This is the expected result
+----+-------+
| id | Value |
+----+-------+
| 1 | 46 |
| 2 | 48 |
| 3 | 33.5 |
+----+-------+
I have calculated it using ROWS N PRECEDING but it appears that this way I average N preceding + last row, and I want to exclude the last row (which is the most recent date in my case).
Here is my query:
SELECT ID,
(avg(Value) OVER(
PARTITION BY ID
ORDER BY Date
ROWS 9 PRECEDING )) as avg9
FROM t1
Then define your window in full using both the start and ends with BETWEEN:
SELECT ID,
(AVG(Value) OVER (PARTITION BY ID ORDER BY Date ROWS BETWEEN 9 PRECEDING AND 1 PRECEDING)) AS avg9
FROM t1;
Why not just filter:
select id, avg(value)
from t1
where date < '2020-11-26'
group by id;
If you want the date to be flexible -- say the most recent value for each date, then:
select id, avg(value)
from (select t1.*,
max(date) over (partition by id) as max_date
from t1
) t1
where date < max_date
group by id;
Do a row_number() over (Partition by id ORDER BY [Date] DESC). This will give a rank = 1 to the row with latest date. Wrap it within a CTE and then calculate avg for each partition where RANK > 1. Please check syntax.
;with a as
(
select id, value, Date, row_number() over (partition by id order by date
desc) as RN
)
select id, avg(Value) from a group by id where r.RN > 1

Aggregate quantity columns per distinct date in table sql

I want to sum quantity column from first date in table (2016-02-17 in this table) until per each distinct date in the table. Result relation should contains sum of quantities per each distinct date in table.
how can I write a query for this in sql server?
ID| quantity | date
---+----------+-----
18 | 6 | 2016-02-17 00:00:00.000
19 | 6 | 2016-02-17 00:00:00.000
18 | 4 | 2016-02-17 00:00:00.000
19 | 3 | 2016-02-18 00:00:00.000
18 | 1 | 2016-02-18 00:00:00.000
19 | 5 | 2016-02-18 00:00:00.000
18 | 6 | 2016-02-19 00:00:00.000
19 | 7 | 2016-02-19 00:00:00.000
18 | 8 | 2016-02-19 00:00:00.000
19 | 9 | 2016-02-19 00:00:00.000
Expected output:
| Date | quantity |
|------------|----------|
| 2016-02-17 | 16 |
| 2016-02-18 | 25 |
| 2016-02-19 | 55 |
Aggregate function SUM with GROUP BY will give you the sum values for the Distinct dates.
SELECT Date,
SUM(quantity) OVER(ORDER BY Date) quantity
FROM(
SELECT DATE, SUM(quantity) quantity
FROM Your_Table
GROUP BY DATE
)A
Check the SQL Fiddle for reference.
If you want the result for ID specific, use this. The PARTITION will make the difference.
SELECT Id, Date,
SUM(quantity) OVER(PARTITION BY ID ORDER BY Date) quantity
FROM(
SELECT Id, DATE, SUM(quantity) quantity
FROM A
GROUP BY Id, DATE
)A
You do not need a subquery or CTE to use window functions with aggregation:
SELECT DATE, SUM(quantity) as day_quantity,
SUM(SUM(quantity)) OVER (ORDER BY DATE) as running_quantity
FROM Your_Table
GROUP BY DATE
ORDER BY DATE;
If you want the results ordered by date (as implied by your result set), you should include an explicit ORDER BY.
Another approach is
WITH
b as (
Select my_date,
SUM(quantity) Over(order by my_date rows between unbounded preceding and current row) running_total
from main_table
)
SELECT my_date, max(running_total) running_total
from b group by dt

SQL - How can I count days by comparing current row to the 1st row?

I have a table as below in the database, how can I write a SQL to show the expected result?
first_date: the first order_date on the table ORDER BY order_date ASC
days_to_date: (order_date - first_date) in number of days
My table:
id | order_date | order_ref
---+------------------------
1 | 2015-03-01 | BC101
2 | 2015-03-01 | BC102
3 | 2015-03-02 | BC103
4 | 2015-03-03 | BC104
Expected result:
id | order_date | first_date | days_to_date
---+------------+------------+-------------
1 | 2015-03-01 | 2015-03-01 | 0
2 | 2015-03-01 | 2015-03-01 | 0
3 | 2015-03-02 | 2015-03-01 | 1
4 | 2015-03-03 | 2015-03-01 | 2
Other notes:
I'm using HSQLDB 2.0.0, but prefer solving the problem of getting the first_date displayed on every row in general cases if that's possible
Thanks in advance
Try
select id, order_date,
(select min(order_date) from your_table) as first_date,
datediff('day', (select min(order_date) from your_table), order_date) as days_to_date
from your_table
order by order_date