Joins and/or Sub queries or Ranking functions - sql

I have a table as follows:
Order_ID
Ship_num
Item_code
Qty_to_pick
Qty_picked
Pick_date
1111
1
1
3000
0
Null
1111
1
2
2995
1965
2021-05-12
1111
2
1
3000
3000
2021-06-24
1111
2
2
1030
0
Null
1111
3
2
1030
1030
2021-08-23
2222
1
3
270
62
2021-03-18
2222
1
4
432
0
Null
2222
2
3
208
0
Null
2222
2
4
432
200
2021-05-21
2222
3
3
208
208
2021-08-23
2222
3
4
232
200
2021-08-25
From this table,
I only want to show the rows that has the latest ship_num information, not the latest pick_date information (I was directed to a question like this that needed to return the rows with the latest entry time, I am not looking for that) for an order i.e., I want it as follows
Order_ID
Ship_num
Item_code
Qty_to_pick
Qty_picked
Pick_date
1111
3
2
1030
1030
2021-08-23
2222
3
3
208
208
2021-08-23
2222
3
4
232
200
2021-08-25
I tried the following query,
select order_id, max(ship_num), item_code, qty_to_pick, qty_picked, pick_date
from table1
group by order_id, item_code, qty_to_pick, qty_picked, pick_date
Any help would be appreciated.
Thanks in advance.

Using max(ship_num) is a good idea, but you should use the analytic version (with an OVER clause).
select *
from
(
select t.*, max(ship_num) over (partition by order_id) as orders_max_ship_num
from table1 t1
) with_max
where ship_num = orders_max_ship_num
order by order_id, item_code;

You can get this using the DENSE_RANK().
Query
;with cte as (
select rnk = dense_rank()
over (Partition by order_id order by ship_num desc)
, *
from table_name
)
Select *
from cte
Where rnk =1;

Related

MSSQL - Running sum with reset after gap

I have been trying to solve a problem for a few days now, but I just can't get it solved. Hence my question today.
I would like to calculate the running sum in the following table. My result so far looks like this:
PersonID
Visit_date
Medication_intake
Previous_date
Date_diff
Running_sum
1
2012-04-26
1
1
2012-11-16
1
2012-04-26
204
204
1
2013-04-11
0
1
2013-07-19
1
1
2013-12-05
1
2013-07-19
139
343
1
2014-03-18
1
2013-12-05
103
585
1
2014-06-24
0
2
2014-12-01
1
2
2015-03-09
1
2014-12-01
98
98
2
2015-09-28
0
This is my desired result. So only the running sum over contiguous blocks (Medication_intake=1) should be calculated.
PersonID
Visit_date
Medication_intake
Previous_date
Date_diff
Running_sum
1
2012-04-26
1
1
2012-11-16
1
2012-04-26
204
204
1
2013-04-11
0
1
2013-07-19
1
1
2013-12-05
1
2013-07-19
139
139
1
2014-03-18
1
2013-12-05
103
242
1
2014-06-24
0
2
2014-12-01
1
2
2015-03-09
1
2014-12-01
98
98
2
2015-09-28
0
I work with Microsoft SQL Server 2019 Express.
Thank you very much for your tips!
This is a gaps and islands problem, and one approach uses the difference in row numbers method:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY PersonID
ORDER BY Visit_date) rn1,
ROW_NUMBER() OVER (PARTITION BY PersonId, Medication_intake
ORDER BY Visit_date) rn2
FROM yourTable
)
SELECT PersonID, Visit_date, Medication_intake, Previous_date, Date_diff,
CASE WHEN Date_diff IS NOT NULL AND Medication_intake = 1
THEN SUM(Date_diff) OVER (PARTITION BY PersonID, rn1 - rn2
ORDER BY Visit_date) END AS Running_sum
FROM cte
ORDER BY PersonID, Visit_date;
Demo
The CASE expression in the outer query computes the rolling sum for date diff along islands of records having a medication intake value of 1. For other records, or for records where date diff be null, the value generated is simply null.

Duplicates with condition (SQL)

I would like to get the number of duplicates for article_id for each merchant_id, where the zip_code is identical. Please see example below:
Table
merchant_id article_id zip_code
1 4555 1000
1 4555 1003
1 4555 1000
1 3029 1000
2 7539 1005
2 7539 1005
2 7539 1002
2 1232 1006
3 5555 1000
3 5555 1001
3 5555 1001
3 5555 1001
Output Table
merchant_id count_duplicate zip_code
1 2 1000
2 2 1005
3 3 1001
This is the query that I am currently using but I am struggling to include the zip_code condition:
SELECT merchant_id
,duplicate_count
FROM main_table mt
JOIN(select article_id, count(*) AS duplicate_count
from main_table
group by article_id
having count(article_id) =1) mt_1
ON mt.article_id ON mt_1.article_id = mt.article_id
This seems to return what you want. I'm not sure why article_id is not included in the result set:
select merchant_id, zip_code, count(*)
from main_table
group by merchant_id, article_id, zip_code
having count(*) > 1

duplicates with condition

I would like to get the number of duplicates for article_id for each merchant_id, where the zip_code is not identical. Please see example below:
Table
merchant_id article_id zip_code
1 4555 1000
1 4555 1003
1 4555 1002
1 3029 1000
2 7539 1005
2 7539 1005
2 7539 1002
2 1232 1006
3 5555 1000
3 5555 1001
3 5555 1002
3 5555 1003
Output Table
merchant_id count_duplicate
1 3
2 2
3 4
This is the query that I am currently using but I am struggling to include the zip_code condition:
SELECT merchant_id
,duplicate_count
FROM main_table mt
JOIN(select article_id, count(*) AS duplicate_count
from main_table
group by article_id
having count(article_id) >1) mt_1
ON mt.article_id ON mt_1.article_id = mt.article_id
If I understand correctly, you can use two levels of aggregation:
SELECT merchant_id, SUM(num_zips)
FROM (SELECT merchant_id, article_id, COUNT(DISTINCT zip_code) AS num_zips
FROM main_table
GROUP BY merchant_id, article_id
) ma
WHERE ma.num_zips > 1
GROUP BY merchant_id;

List the last two records for each id

Good Afternoon!
I'm having trouble list the last two records each idmicro
Ex:
idhist idmicro idother room unit Dtmov
100 1102 0 8 coa 2009-10-23 10:40:00.000
101 1102 0 1 coa 2009-10-28 10:40:00.000
102 1102 0 2 dib 2008-10-24 10:40:00.000
103 1201 0 6 diraf 2008-10-23 10:40:00.000
104 1201 0 7 diraf 2009-10-21 10:40:00.000
105 1201 0 4 dimel 2008-10-22 10:40:00.000
Would look like this:
ex:
result
idhist idmicro idoutros room unit Dtmov
101 1102 0 1 coa 2009-10-28 10:40:00.000
102 1102 0 2 dib 2008-10-24 10:40:00.000
103 1201 0 6 diraf 2008-10-22 10:40:00.000
104 1201 0 7 diraf 2009-10-21 10:40:00.000
I'm starting to delve into SQL and am having trouble finding this solution
Sorry
Thank you.
EDIT: I am using SQL server, and I made no query.
Yes! is based on the date and time
You can do the same thing with an imbricated SELECT statement.
SELECT *
FROM (
SELECT row_number() OVER (
PARTITION BY idmicro ORDER BY idhist
) AS ind
,*
FROM data
) AS initialResultSet
WHERE initialResultSet.ind < 3
Here is a sample SQLFiddle with how this query works.
WITH etc
AS (
SELECT *
,row_number() OVER (
PARTITION BY idmicro ORDER BY idhist
) AS r
,count() OVER (
PARTITION BY idmicro ORDER BY idhist
) cfrom TABLE
)
SELECT *
FROM etc
WHERE r > c - 2
Use row_number and over partition
SELECT *
FROM (
SELECT *, row_number() OVER (PARTITION BY idmicro ORDER BY idhist desc) AS rownum
FROM data
) AS initialResultSet
WHERE initialResultSet.rownum<=2

Update Table column with values for other column

I have a table along these lines:
Client | Date | Value 1 | Value 2 |
1 2013-11-08 159 159
1 2013-11-09 254 254
1 2013-12-05 512 512
1 2014-01-02 1200 1200
2 2013-11-10 189 189
2 2013-11-15 289 289
2 2013-12-22 585 585
2 2014-01-06 1650 1650
I need to update the table in SQL to look like this:
Client | Date | Value 1 | Value 2 |
1 2013-11-08 159 1200
1 2013-11-09 254 1200
1 2013-12-05 512 1200
1 2014-01-02 1200 1200
2 2013-11-10 189 1650
2 2013-11-15 289 1650
2 2013-12-22 585 1650
2 2014-01-06 1650 1650
The idea is that for each Client, Value 2 will become Value 1 where Date is most recent.
In SQL Server the best best thing to use is CTE with UPDATE statement. The query below demonstrates the syntax for what you need to do. All you have to do is substitute your table name and columns names.
;WITH MyUpdate
AS ( SELECT ClientId
,Value1
,ROW_NUMBER() OVER ( PARTITION BY ClientId ORDER BY MyDate DESC ) AS RowNum
FROM MyTable)
UPDATE MyTable
SET MyTable.Value2 = MyUpdate.Value1
FROM MyTable
INNER JOIN MyUpdate
ON MyUpdate.ClientID = MyTable.ClientID
AND RowNum = 1
Try this:
UPDATE TABLE1 T2 SET Value2 =
(SELECT T1.Value2 FROM TABLE1 T1 WHERE T1.Client = T2.Client AND
T1.Date = (SELECT MAX(T3.Date) FROM TABLE1 T3
WHERE T2.Client = T3.Client GROUP BY Client));
ORACLE