Calculate the difference from the minimum value within a group - sql

Given the following table:
| id| Date |
| 1 | 04-01-2016 |
| 1 | 04-07-2016 |
| 1 | 04-09-2016 |
| 2 | 04-06-2016 |
| 2 | 04-03-2016 |
| 2 | 04-10-2016 |
I would like to have a column with the number of days between each day and the minimum day within an id grouping.
id | date | day_count
---+------------+------------
1 | 04-01-2016 | 0 (days between 04-01-2016 and 04-01-2016)
1 | 04-04-2016 | 3 (days between 04-04-2016 and 04-01-2016)
1 | 04-08-2016 | 7
2 | 04-17-2016 | 14 (days between 04-017-2016 and 04-03-2016)
2 | 04-03-2016 | 0
2 | 04-10-2016 | 7

By using Window Function and Datediff we can achieve below result
DECLARE #Table1 TABLE
(id int, date datetime)
;
INSERT INTO #Table1
(id, date)
VALUES
(1, '2016-04-01 05:30:00'),
(1, '2016-04-04 05:30:00'),
(1, '2016-04-08 05:30:00'),
(2, '2016-04-03 05:30:00'),
(2, '2016-04-17 05:30:00'),
(2, '2016-04-20 05:30:00')
;
Script
select *
, datediff(day, min(Date) over (partition by [ID]), Date)Cnt
from #Table1

Related

Find the period of occurence of a value in table

I have a table with the following data.
+------------+---------+
| Date | Version |
+------------+---------+
| 1/10/2019 | 1 |
| .... | |
| 15/10/2019 | 1 |
| 16/10/2019 | 2 |
| .... | |
| 26/10/2019 | 2 |
| 27/10/2019 | 1 |
| .... | |
| 30/10/2019 | 1 |
+------------+---------+
I need to find the period of occurrence for version in the table.
Eg:Suppose I need to get Version 1 occurence details which is present from 1/10/2019 to 15/10/2019 and from 27/10/2019 to 30/10/2019. How can i query the database for such a result?
I have tried many ways but not able to produce the desired result .I even doubt this is possible using a query!
Any inputs are highly appreciated.
Expected output:
+---------+-------------+-------------+
| Version | Period from | Period To |
+---------+-------------+-------------+
| 1 | 1/10/2019 | 15/10/2019 |
| 2 | 16/10/2019 | 26/10/2019 |
| 1 | 27/10/2019 | 30/10/2019 |
+---------+-------------+-------------+
This is gaps and Islands question.
Try this
DECLARE #SampleData TABLE ( [Date] DATE, [Version] INT)
INSERT INTO #SampleData ([Date], [Version])
VALUES
('01-10-2019', 1), ('02-10-2019', 1), ('15-10-2019', 1),
('16-10-2019', 2), ('17-10-2019', 2),('26-10-2019', 2),
('27-10-2019', 1), ('28-10-2019', 1), ('30-10-2019', 1)
SELECT
Y.[Version]
,PeriodFrom = MIN(Y.[Date])
,PeriodTo = MAX(Y.[Date])
FROM(
SELECT
X.[Version]
,X.[Date]
,ISLAND = RN-ROW_NUMBER()OVER( PARTITION BY X.[Version] ORDER BY X.[Date])
FROM(
SELECT
RN=ROW_NUMBER()OVER( ORDER BY S.[Date])
,S.[Date]
,S.[Version]
FROM
#SampleData S
) X
) Y
GROUP BY
Y.[Version], Y.ISLAND
ORDER BY
PeriodFrom
Output
Version PeriodFrom PeriodTo
1 2019-10-01 2019-10-15
2 2019-10-16 2019-10-26
1 2019-10-27 2019-10-30

How to get record by date from 1 table and update other table in Postgresql?

I have two tables. In one table(order_produt) have multiple records by date and other table(Transfer_product) also multiple record by date. order_product table have correct record. i want update my transfer_product table with order_product table by date range.
order_product_table
-------------------------
id | date | Product_id | value
-------------------------------------------
1 | 2017-07-01 | 2 | 53
2 | 2017-08-05 | 2 | 67
3 | 2017-10-02 | 2 | 83
4 | 2018-01-20 | 5 | 32
5 | 2018-05-01 | 5 | 53
6 | 2008-08-05 | 6 | 67
Transfer_product_table
----------------------------
id | date | Product_id | value
--------------------------------------------
1 | 2017-08-01 | 2 | 10
2 | 2017-10-06 | 2 | 20
3 | 2017-12-12 | 2 | 31
4 | 2018-06-25 | 5 | 5
Result(Transfer_product_table)
--------------------------------
id | date | Product_id | value
--------------------------------------------
1 | 2017-08-01 | 2 | 53
2 | 2017-10-06 | 2 | 83
3 | 2017-12-12 | 2 | 83
4 | 2018-06-25 | 5 | 53
I want by date value update like you can see Result table.
i use query partion by but this is not what i want.
UPDATE Transfer_product_table imp
SET value = sub.value
FROM (SELECT product_id,value
,ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY orderdate DESC)AS Rno
FROM order_product_table
where orderdate between '2017-07-01' and '2019-10-31') sub
WHERE imp.product_id = sub.product_id
and sub.Rno=1
and imp.date between '2017-07-01' and '2019-10-31'
This is pretty straightforward using postgres' awesome daterange type.
with order_product_table as (
select * from (
VALUES (1, '2017-07-01'::date, 2, 53),
(2, '2017-08-05', 2, 67),
(3, '2017-10-02', 2, 83),
(4, '2018-01-20', 5, 32),
(5, '2018-05-01', 5, 53),
(6, '2008-08-05', 6, 67)
) v(id, date, product_id, value)
), transfer_product_table as (
select * from (
VALUES (1, '2017-08-01'::date, 2, 10),
(2, '2017-10-06', 2, 20),
(3, '2017-12-12', 2, 31),
(4, '2018-06-25', 5, 5)
) v(id, date, product_id, value)
), price_ranges AS (
select product_id,
daterange(date, lead(date) OVER (PARTITION BY product_id order by date), '[)') as pricerange,
value
FROM order_product_table
)
SELECT id,
date,
transfer_product_table.product_id,
price_ranges.value
FROM transfer_product_table
JOIN price_ranges ON price_ranges.product_id = transfer_product_table.product_id
AND date <# pricerange
ORDER BY id
;
id | date | product_id | value
----+------------+------------+-------
1 | 2017-08-01 | 2 | 53
2 | 2017-10-06 | 2 | 83
3 | 2017-12-12 | 2 | 83
4 | 2018-06-25 | 5 | 53
(4 rows)
Basically, we figure out the price at any given date by using the order_product_table. We get the price between the current date (inclusive) and the next date (exclusive) with this:
daterange(date, lead(date) OVER (PARTITION BY product_id order by date), '[)') as pricerange,
Then we simply join to this on the condition that the product_ids match and that date in the transfer_product_table is contained by the pricerange.

SQL Query to count number of records must match total number of records

I have 2 tables as
Result Master
+------+-------------+
| QnID | Description |
+------+-------------+
| 1 | Qn1 |
| 2 | Qn2 |
| 3 | Qn3 |
| 4 | Qn4 |
| 5 | Qn5 |
+------+-------------+
Result Details
+----+------+--------+--------+
| ID | QnID | TCDesc | Result |
+----+------+--------+--------+
| 1 | 1 | TC1 | PASS |
| 2 | 1 | TC2 | FAIL |
| 3 | 1 | TC3 | PASS |
| 4 | 2 | TC1 | PASS |
| 5 | 3 | TC1 | PASS |
| 6 | 3 | TC1 | PASS |
| 7 | 3 | TC3 | PASS |
+----+------+--------+--------+
I need a query which will return following result:
+----+------+--------+
| ID | QnID | Result |
+----+------+--------+
| 1 | 2 | PASS |
| 2 | 3 | PASS |
| 3 | 4 | ERROR |
| 4 | 5 | ERROR |
+----+------+--------+
Conditions:
each question will have different number of testcase "ResultDetails", I need to select questions for which all the test case get passsed (number of entries for a particular question must be same as number of test cases passed for the same) or Error (ResultDetail doesn't have an entry for a question).
Can anyone please help me with a query, thank you.
You can get the desired results using a common table expression and conditional aggregation.
First, create and populate sample tables (Please save us this step in your future questions):
DECLARE #ResultMaster AS TABLE
(
QnID int,
Description char(3)
);
INSERT INTO #ResultMaster (QnID, Description) VALUES
(1, 'Qn1'),
(2, 'Qn2'),
(3, 'Qn3'),
(4, 'Qn4'),
(5, 'Qn5');
DECLARE #ResultDetails AS TABLE
(
ID int,
QnID int,
TCDesc char(3),
Result char(4)
);
INSERT INTO #ResultDetails VALUES
(1, 1, 'TC1', 'PASS'),
(2, 1, 'TC2', 'FAIL'),
(3, 1, 'TC3', 'PASS'),
(4, 2, 'TC1', 'PASS'),
(5, 3, 'TC1', 'PASS'),
(6, 3, 'TC1', 'PASS'),
(7, 3, 'TC3', 'PASS');
Then, use a common table expression to calculate the number of pass details and a simple count to get the number of total details:
WITH CTE AS
(
SELECT M.QnId,
COUNT(CASE WHEN Result = 'PASS' THEN 1 END) As CountPass,
COUNT(Result) As CountDetails
FROM #ResultMaster As M
LEFT JOIN #ResultDetails As D ON M.QnId = D.QnId
GROUP BY M.QnId
)
Then, select from that cte:
SELECT ROW_NUMBER() OVER(ORDER BY QnId) AS Id,
QnId,
CASE WHEN CountDetails = 0 THEN
'ERROR'
ELSE
'PASS'
END
FROM CTE
WHERE CountPass = CountDetails
Results:
+----+------+--------+
| ID | QnID | Result |
+----+------+--------+
| 1 | 2 | PASS |
| 2 | 3 | PASS |
| 3 | 4 | ERROR |
| 4 | 5 | ERROR |
+----+------+--------+
You can see a live demo on rextester.

Trying to add total for individual for every month/year

" We have two tables. One for hours which have been sent to a vendor (Master) and one for the hours we are about to send (Load). I am attempting to sum the hours based on month and year for each individual with subtotals. We want to find those individuals who have more than 300 hours for a particular month.
CREATE TABLE MasterTabletesting(
ID CHAR(9) NOT NULL
,Workdate DATE NOT NULL
,Emp CHAR(30) NOT NULL
,HoursWorked DECIMAL(18,2) NOT NULL);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','7502',24);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','21874',128);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','7502',166);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','7508',180);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','5501',180);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','21037',23);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('66','20160831','83641',22);
CREATE TABLE LoadTabletesting(
ID CHAR(9) NOT NULL
,Workdate CHAR(8) NOT NULL
,Emp CHAR(30) NOT NULL
,HoursWorked DECIMAL(18,2) NOT NULL);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('8','07312016','7500',24);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('6','07312016','21974',128);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','07312016','7500',166);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','08312016','7500',180);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('88','08312016','5507',180);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('23','08312016','21012',23);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('55','08312016','83667',22);}
The date in the load table is a char variable type which I have resolved with cast. My approach has been to place the necessary data from both tables in a view titled "Over300agtest:
SELECT ID AS 'ID'
,Employer AS 'Emp'
,month(WorkDate) AS 'Mnth'
,year(WorkDate) AS 'Yr'
,HoursworkedAS 'Hrs'
,’amt’ as ‘Table’
FROM Mastertabletesting
WHERE HoursWorked IS NOT NULL
GROUP BY ID, Employer, month(WorkDate), year(WorkDate)
UNION all
SELECT ID AS 'ID'
,Employer AS 'Emp'
,month(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE)) AS 'Mnth'
,YEAR(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE)) AS 'Yr'
,hoursworked AS 'Hrs'
,‘alt’ as ‘Table’
FROM Loadtabletesting
WHERE HoursWorked IS NOT NULL
GROUP BY ID, Employer, month(CAST((RIGHT(workdate, 4) +LEFT workdate,4)) AS DATE)), year(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE))
Then I am using a common table expression to find those which have over 300 hours in a particular month and then using a query to join to the CTE in order to add the employer they worked for. Any suggestions on how to add a line under the hours column for each month for the total would be greatly appreciated.
with monthsum as(
Select ID as 'ID'
, mnth as 'mnth'
, yr as 'yr'
,SUM(hrs)as 'TotalHrs'
From over300agtest
Group by ID, mnth, yr
having SUM(hrs) > 300)
Select ms.ID
,ms.mnth
,ms.yr
,emp
,hrs
,o3.[table]
,totalhrs
From monthsum ms left outer join over300agtest o3
on ms.ID = o3.ID and ms.mnth = o3.mnth and ms.yr =o3.yr
Order by ms.ID, ms.yr asc, ms.mnth asc
Here is the current output:
+----+------+------+-------+-----+-------+----------+
| ID | mnth | yr | emp | hrs | table | totalhrs |
+----+------+------+-------+-----+-------+----------+
| 25 | 7 | 2016 | 7502 | 24 | AMT | 484 |
| 25 | 7 | 2016 | 21874 | 128 | AMT | 484 |
| 25 | 7 | 2016 | 7502 | 166 | AMT | 484 |
| 25 | 7 | 2016 | 7500 | 166 | ALT | 484 |
| 72 | 8 | 2016 | 7508 | 180 | AMT | 563 |
| 72 | 8 | 2016 | 5501 | 180 | AMT | 563 |
| 72 | 8 | 2016 | 21037 | 23 | AMT | 563 |
| 72 | 8 | 2016 | 7500 | 180 | ALT | 563 |
+----+------+------+-------+-----+-------+----------+
Here is the output I am going for:
+-------+------+------+-------+-----+-------+
| ID | mnth | yr | emp | hrs | table |
+-------+------+------+-------+-----+-------+
| 25 | 7 | 2016 | 7502 | 24 | AMT |
| 25 | 7 | 2016 | 21874 | 128 | AMT |
| 25 | 7 | 2016 | 7502 | 166 | AMT |
| 25 | 7 | 2016 | 7500 | 166 | ALT |
| Total | | | | 484 | |
| 72 | 8 | 2016 | 7508 | 180 | AMT |
| 72 | 8 | 2016 | 5501 | 180 | AMT |
| 72 | 8 | 2016 | 21037 | 23 | AMT |
| 72 | 8 | 2016 | 7500 | 180 | ALT |
| Total | | | | 563 | |
+-------+------+------+-------+-----+-------+
I suggest this approach. You should be able to work out the specifics.
select convert(char(6), cast(workdate as date), 120) yearMonth
, sum(hrs) totalHours
from etc
group by convert(char(6), cast(workdate as date), 120)
having sum(hrs) > 300

How to use joins and sum() in SQL Server query

I have two tables Items and Transactions. In the items table, all the items are listed. In the transactions table it is where a particular employee can request for an item depending on the quantity that he/she requested.
How to use joins to merge the data from two tables that will compute for the balance quantity of each item?
Note: (Quantity Balance = Quantity - TR_Qty)
ITEMS table:
| ID | ITEM | UNIT | QUANTITY | PRICE |
| 1 | Perfume | btl. | 50 | 200.00 |
| 2 | Battery | pc. | 100 | 25.00 |
| 3 | Milk | can | 250 | 70.00 |
| 4 | Soap | pack | 400 | 150.00 |
TRANSACTIONS table:
| ID | ITEM_ID | TR_QTY | REQUSETOR | PROCESSOR | Date |Time |
| 1 | 1 | 20 | A. Jordan | K. Koslav | 12-22-2014 |09:00|
| 2 | 2 | 8 | B. Wilkins | Z. Flores | 12-22-2014 |10:03|
| 3 | 3 | 80 | C. Potran | A. Mabag | 12-26-2014 |14:23|
| 4 | 3 | 45 | D. Korvak | D. Sanchez | 12-28-2014 |15:33|
| 5 | 4 | 22 | C. Carvicci | A. Flux | 12-31-2014 |16:02|
| 6 | 1 | 18 | F. Sansi | N. Mahone | 01-22-2015 |08:45|
| 7 | 4 | 14 | Z. Gorai | M. Sucre | 01-30-2015 |16:33|
| 8 | 2 | 7 | L. ZOnsey | P. Panchito | 02-11-2015 |17:22|
Desired output:
| ID | ITEM | QUANITY BALANCE|
| 1 | Perfume | 462 |
| 2 | Battery | 85 |
| 3 | Milk | 125 |
| 4 |Soap | 364 |
Try this:
DECLARE #Items TABLE(ID INT, Item NVARCHAR(10), Q INT)
DECLARE #Transactions TABLE(ID INT, ItemID INT, TQ INT)
INSERT INTO #Items VALUES
(1, 'Perfume', 500),
(2, 'Battery', 100),
(3, 'Milk', 250),
(4, 'Soap', 400)
INSERT INTO #Transactions VALUES
(1, 1, 20),
(2, 2, 8),
(3, 3, 80),
(4, 3, 45),
(5, 4, 22),
(6, 1, 18),
(7, 4, 14),
(8, 2, 7)
SELECT i.ID, i.Item, MAX(i.Q) - ISNULL(SUM(t.TQ), 0) AS Balance
FROM #Items i
LEFT JOIN #Transactions t ON t.ItemID = i.ID
GROUP BY i.ID, i.Item
ORDER BY i.ID
Output:
ID Item Balance
1 Perfume 462
2 Battery 85
3 Milk 125
4 Soap 364
You can do it for example by using outer apply and creating the sum of quantities in there:
select
I.ID,
I.ITEM,
I.QUANTITY - isnull(T.QUANTITY, 0) as BALANCE
from
ITEMS I
outer apply (
select sum(TR_QTY) as QUANTITY
from TRANSACTIONS T
where T.ITEM_ID = I.ID
) T
SELECT ITEM , ( SELECT (SUM(TRANSACTIONS.TR_QTY)-ITEMS.TR_QTY) FROM TRANSACTIONS WHERE TRANSACTIONS.ITEM_ID = ITEMS.ID ) AS QUANITY BALANCE FROM ITEMS
Field name and table name is as you mentioned in query ( you should change that as space is not valid for field or table name )