TSQL : conditional query - sql

I am trying to find a way to get results where the Occupancy in the latest Inspection_date and the one before the last are not equal.
In this example only number RoomID 2 will be the only result because: the Occupancy for OrderID 201 = 'Vacant' <> to the Occupancy for OrderID 202 = 'Occupied'.
I have the beginning of the query but cannot seem to find a good logic to end the query.
| RoomID | OrderID | Occupancy | rn |
+--------+---------+-----------+----+
| 01 | 101 | Vacant | 1 |
| 01 | 102 | Vacant | 2 |
| 01 | 103 | Occupied | 3 |
| 01 | 104 | Vacant | 4 |
| 02 | 201 | Vacant | 1 |
| 02 | 202 | Occupied | 2 |
| 02 | 203 | Vacant | 3 |
| 03 | 301 | Occupied | 1 |
| 03 | 302 | Occupied | 2 |
| 03 | 303 | Occupied | 3 |
| 03 | 304 | Occupied | 4 |
| 04 | 401 | Occupied | 1 |
| 04 | 402 | Occupied | 2 |
| 04 | 403 | Vacant | 3 |
| 04 | 404 | Occupied | 4 |
SELECT i.room_number, order_number, Occupancy , row_number() OVER(PARTITION BY room_number ORDER BY Inspection_date DESC) rn
FROM #inspection_data i

In SQL Server 2012+, you can use lag(), so something like this:
SELECT i.*
FROM (SELECT i.room_number, order_number, Occupancy ,
ROW_NUMER() OVER (PARTITION BY room_number ORDER BY Inspection_date DESC) as seqnum,
LAG(Occupancy) OVER (PARTITION BY room_number ORDER BY Inspection_date) as prev_Occupancy
FROM #inspection_data i
) i
WHERE prev_Occupancy <> Occupancy AND seqnum = 1 ;

Related

How to get Max date and sum of its rows SQL

I have following table,
+------+-------------+----------+---------+
| id | date | amount | amount2 |
+------+-------------+----------+---------+
| | | | 500 |
| 1 | 1/1/2020 | 1000 | |
+------+-------------+----------+---------+
| | | | 100 |
| 1 | 1/3/2020 | 1558 | |
+------+-------------+----------+---------+
| | | | 200 |
| 1 | 1/3/2020 | 126 | |
+------+-------------+----------+---------+
| | | | 500 |
| 2 | 2/5/2020 | 4921 | |
+------+-------------+----------+---------+
| | | | 100 |
| 2 | 2/5/2020 | 15 | |
+------+-------------+----------+---------+
| | | | 140 |
| 2 | 1/1/2020 | 5951 | |
+------+-------------+----------+---------+
| | | | 10 |
| 2 | 1/2/2020 | 1588 | |
+------+-------------+----------+---------+
| | | | 56 |
| 2 | 1/3/2020 | 1568 | |
+------+-------------+----------+---------+
| | | | 45 |
| 2 | 1/4/2020 | 12558 | |
+------+-------------+----------+---------+
I need to get each Id's max date and its amount and amount2 summations, how can I do this. according to above data, I need following output.
+------+-------------+----------+---------+
| | | | 300 |
| 1 | 1/3/2020 | 1684 | |
+------+-------------+----------+---------+
| | | | 600 |
| 2 | 2/5/2020 | 4936 | |
+------+-------------+----------+---------+
How can I do this.
Aggregate and use MAX OVER to get the IDs' maximum dates:
select id, [date], sum_amount, sum_amount2
from
(
select
id, [date], sum(amount) as sum_amount, sum(amount2) as sum_amount2,
max([date]) over (partition by id) as max_date_for_id
from mytable group by id, [date]
) aggregated
where [date] = max_date_for_id
order by id;
first is to use dense_rank() to find the row with latest date
dense_rank () over (partition by id order by [date] desc)
after that, just simply group by with sum() on the amount
select id, [date], sum(amount), sum(amount2)
from
(
select *,
dr = dense_rank () over (partition by id order by [date] desc)
from your_table
) t
where dr = 1
group by id, [date]

How to compare values in several fields for each ID in a table

I've a table that contains alert information for replacement orders.(br)(br)
I need to confirm for each alert that for each Order ID in the alert ID:
The Buyer names are the same
The paid date is different between each alert.
Alert_ID | Order_ID | Buyer_ID | Item | Quantity | Paid_date
01 | 001A | Adam | Apple | 2 | 01/01/2019
01 | 001A | Adam | Orange| 3 | 01/01/2019
01 | 001B | Adam | Apple | 4 | 01/03/2019
01 | 001B | Adam | Orange| 3 | 01/03/2019
01 | 001C | Adam | Apple | 3 | 01/07/2019
01 | 001C | Adam | Orange| 3 | 01/07/2019
02 | 002A | Pam | Banana| 2 | 01/21/2019
02 | 002A | Pam | Grapes| 1 | 01/21/2019
02 | 002B | Pam | Banana| 2 | 01/30/2019
02 | 001B | Pam | Grapes| 4 | 01/30/2019
04 | 004A | Dave | Apple | 2 | 01/01/2019
04 | 004B | Mary | Apple | 3 | 01/01/2019
Initially this was a 1:1 relationship of replacement claims to original claims. I split the table in two by alert_id with the replacement order in one sub query and the original order In the other, then I could compare all the fields I wanted between alerts and orders.
select
*
from
(
with repl as(
select
Alert_ID, Order_ID, Buyer_ID, Paid_date
ROW_NUMBER () over(partition by alert_id order by alert_id, Order_id) AS RN
from <MY ALERT TABLE>
)
SELECT * FROM repl WHERE RN = 1
) A
LEFT JOIN
(
with repl as(
select
Alert_ID, Order_ID, Buyer_ID, Paid_date
ROW_NUMBER () over(partition by alert_id order by alert_id, Order_id) AS RN
from <MY ALERT TABLE>
)
SELECT R1.*
FROM repl R1
LEFT OUTER JOIN repl R2
ON R1.ALERT_ID = R2.ALERT_ID AND R1.RN < R2.RN
WHERE R2.RN IS NULL
) B
ON A.ALERT_ID = B.ALERT_ID
WHERE
a.order_id=b.order_id
and a.buyer_id <> b.buyer_id
and a.paid_date > b.paid_date
This worked fine for 1:1, but with 1:n I'm loosing out on all orders that appear in between the first and last row number.
Expected Result:
Return exceptions to the rules
Alert_ID | Order_ID | Buyer_ID | Item | Quantity | Paid_date
04 | 004A | Dave | Apple | 2 | 01/01/2019
04 | 004B | Mary | Apple | 3 | 01/01/2019
Do you want to get the exceptions -- that is, alter_id/order_id pairs with different names?
If so:
select Alert_ID, Order_ID
from repl
group by Alert_ID, Order_ID
having min(buyer_id) <> max(buyer_id)

T-SQL : partitioning using a case statement

I have the following table :
| RoomID | OrderID | Occupancy | Status |
+--------+---------+-----------+---------------+
| 01 | 101 | Vacant | inspection |
| 01 | 102 | Occupied | Preservation |
| 01 | 103 | Occupied | inspection |
| 01 | 104 | Vacant | inspection |
| 02 | 201 | Vacant | inspection |
| 02 | 202 | Occupied | inspection |
| 02 | 203 | Vacant | inspection |
| 03 | 301 | Vacant | inspection |
| 03 | 302 | Occupied | inspection |
| 03 | 303 | Occupied | Preservation |
| 03 | 304 | Occupied | Preservation |
| 04 | 401 | Occupied | inspection |
| 04 | 402 | Occupied | inspection |
| 04 | 403 | Vacant | Preservation |
| 04 | 404 | Occupied | inspection |
I need to pull my data on a RoomID level where the Occupancy = 'Occupied' and Status = 'Preservation' in any instance of a given RoomID.
The result should look like the following:
| RoomID | Flag |
+--------+---------+
| 01 | 1 |
| 02 | 0 |
| 03 | 1 |
| 04 | 0 |
I have an impression that this is easy but I cannot see it at the moment, thank you in advance for your help !
You can use conditional aggregation.
select roomid,
count(distinct case when Occupancy = 'Occupied' and Status = 'Preservation' then 1 end) flag
from tablename
group by roomid
You can also use the below query using UNION.
;with cte_1
AS
( SELECT DISTINCT RoomId
FROM YourTable
WHERE Occupancy='Occupied' AND Status='Predervation')
SELECT RoomId,1 Status
FROM cte_1
UNON
SELECT DISTINCT RoomId,0 Status
FROM YourTable t
WHERE NOT EXISTS(SELECT 1 FROM cte_1 c
WHERE t.RoomId=c.RoomId)

Select values of a column into one row - SQL Server

I want to select in one row the value of a column that appears in multiple rows, I have the table Solution:
| StudentID | SolutionDate | SolutionTime | SongID |
----------------------------------------------------
| 0824616 | 2015-09-20 | 00:07:00 | 01 |
| 0824616 | 2015-09-20 | 00:05:00 | 02 |
| 0824616 | 2015-09-21 | 00:07:40 | 01 |
| 0824616 | 2015-09-21 | 00:10:00 | 03 |
| 0824616 | 2015-09-23 | 00:04:30 | 03 |
| 0824616 | 2015-09-23 | 00:11:30 | 03 |
I want to group the records by StudentID and SongID.
The expected output is:
| StudentID | SongID | TimeA | TimeB | TimeC |
-------------------------------------------------------
| 0824616 | 01 | 00:07:00 | 00:07:40 | NULL |
| 0824616 | 02 | 00:05:00 | NULL | NULL |
| 0824616 | 03 | 00:10:00 | 00:04:30 | 00:11:30 |
There are 3 records by StudentID-SongID at the most. I'm using SQL Server 2012.
Try with window function first to number the rows and then use conditional aggregation:
;with cte as(select *, row_number() over(partition by studentid, songid
order by solutiondate, solutiontime) rn from tablename)
select studentid,
songid,
max(case when rn = 1 then solutiontime end) as timea,
max(case when rn = 2 then solutiontime end) as timeb,
max(case when rn = 3 then solutiontime end) as timec
from cte
group by studentid, songid

Access SQL : How to retrieve all records from 2 tables (no matter they do not have record in the other table)

I'm creating inventory report mainly to show current qty, sum of qty that was reserved from customers and Total Qty that available .
As I used LEFT JOIN and RIGHT JOIN but it couldn't work, so I'm thinking of UNION function but I could't make it work. Could you please help me. Thank you very much.
tbl_inventory
inv_id | pd_id | inv_qty_act | inv_date | inv_note
1 | 001 | 120 | 20-Sep-12|
2 | 003 | 387 | 1-Oct-12 |
tbl_reserve
res_id | cust_id | res_date | res_duedate | pd_id | res_qty | if_sent | res_note
3 | 10 | 01-Oct-12| 17-Oct-12 | 001 | 135 | |
4 | 9 | 01-Oct-12| 24-Oct-12 | 001 | 253 | |
5 | 22 | 01-Oct-12| 17-Oct-12 | 001 | 132 | |
6 | 2 | 01-Oct-12| 24-Oct-12 | 002 | 446 | |
tbl_product
pd_id | pd_name
001 | des1
002 | des2
003 | des3
tbl_pdtn_startup
pdtn_st_id | pd_id | pdtn_qty_est
2 | 002 | 200
3 | 003 | 100
Output that I want :
pd_id| pd_name| inv_qty_act|pdtn_qty_est| Sum(res_qty)| Total[(inv_qty_est) - Sum(res_qty)]
001 | des1 | 120 | 0 | 520 | -400 -->(120-520)
002 | des2 | 0 | 200 | 446 | -446 -->(0-446)
003 | des3 | 387 | 100 | 0 | 387
what about this?
SELECT
tbl_product.pd_id,
tbl_product.pd_name,
( SELECT Sum(inv_qty_act) FROM tbl_inventory AS t1
WHERE t1.pd_id=tbl_product.pd_id) AS SumOfinv_qty_act,
( SELECT Sum(pdtn_qty_est) FROM tbl_pdtn_startup AS t2
WHERE t2.pd_id =tbl_product.pd_id) AS SumOfpdtn_qty_est,
( SELECT Sum(res_qty) FROM tbl_reserve AS t3
WHERE t3.pd_id=tbl_product.pd_id) AS SumOfres_qty,
IIF(ISNULL([SumOfinv_qty_act]),0,[SumOfinv_qty_act])-
IIF(ISNULL([SumOfres_qty]),0,[SumOfres_qty]) AS Total
FROM
tbl_product;