I have 6 fields
f1,f2,f3,f4,f5,f6
only fields 4 to 6 only vary i want result as single row based on field 1
Eg
name , age, policy_no, proposer_code, entry_date , status
-----------------------------------------------------------------------------
aaa 18 100002 101 20-06-2016 A
aaa 18 100002 101 21-06-2016 B
aaa 18 100002 101 22-06-2016 c
aaa 18 100002 101 24-06-2016 H
aaa 18 100002 101 26-06-2016 p
I want the last row alone only based on proposer code because that is the most recent entry date.
If I understand correctly, you just want to use row_number() like this:
select t.*
from (select t.*,
row_number() over (partition by name order by entry_date desc) as seqnum
from t
) t
where seqnum = 1;
In oracle you can use the below SQL query to achieve the resultset.
select name ,
age,
policy_no,
proposer_code,
entry_date ,
status
from (
select name ,
age,
policy_no,
proposer_code,
entry_date ,
status,
rank()over(partition by name ,age,policy_no, proposer_code order by entry_date desc) rnk
from test
group by name , age, policy_no, proposer_code ,entry_date , status ) a
where a.rnk = 1;
Related
I am developing simple inventory system but I am having hard time getting the accurate stock on hand after calculating the 3 quantities from 3 different tables. My goal is to add the sum of receiving_stock + sum of returning_stock - the outgoing_stock. But if outgoing_stock has no data all the records are null.
Here’s my data and query.
receiving_stock
Prod_ID, Qty
123 10
124 10
returning_stock
Prod_ID, Qty
124 10
125 10
outgoing_stock
No Data Yet
Actual Result:
Prod_id, qty
Null 10
Null 20
Null 10
Desired Result:
Prod_id, qty
123 10
124 20
125 10
Query:
Select prod_id, isnull(qty,0)-isnull(sold,0) on-hand
Select prod_id, sum(qty) qty
(
select prod_id,qty
From receiving_stock
Union all
select prod_id,qty
From returning_stock
) Za
Group by prod_id
) Zb
Left join
(
From
Select prod_id, sum(qty) sold
From outgoing_stock
Group by prod_id
) zc
) zd
On
Zb.prod_id=zd.prod_id
You can include the third table in UNION ALL with a negative quantity :
SELECT prod_id,qty
From receiving_stock
UNION ALL
SELECT prod_id,qty
From returning_stock
UNION ALL
SELECT prod_id, -qty
From outgoing_stock
I am working on one of requirement the raw data is in following format
Requirement - Startdate should be the date when status changed to 1 and enddate should be the 1st date after the record status changed from 1 to any other number.
Customer
Status
Date
A123
0
7/2/2021
A123
0
7/15/2021
A123
0
7/22/2021
A123
1
8/18/2021
A123
1
9/8/2021
A123
0
12/1/2021
A123
0
1/21/2022
A123
1
3/6/2022
A123
1
3/7/2022
A123
0
3/15/2022
B123
1
1/1/2022
B123
0
1/6/2022
C123
1
1/2/2022
C123
2
1/8/2022
C123
0
1/9/2022
expected output
Customer
StartDate
EndDate
A123
8/18/2021
12/1/2021
A123
9/8/2021
12/1/2021
A123
3/6/2022
3/15/2022
A123
3/7/2022
3/15/2022
B123
1/1/2022
1/6/2022
C123
1/2/2022
1/8/2022
Query I tried to get the output is below, I am getting the output for Customer B123 and C123, but not for A123 as expected.
Query Explanation - In 1st part of query I am taking all the records with status = 1 and in next part taking only those records where status is not equal to 1, and joining these 2 datasets based on Customer and row number generated.
SELECT A.[Customer],A.StartDate,B.EndDate
from
(
SELECT [Customer],MIN(Date) AS STARTDATE,[Status],RANK() OVER (PARTITION BY [STATUS] ORDER BY Date ASC) AS ROWNUM
FROM table1
WHERE [STATUS] = 1
GROUP BY Customer,Date,[Status]
) A
LEFT JOIN
(
SELECT [Customer],MIN(Date) AS ENDDATE,[Status],RANK() OVER (PARTITION BY [STATUS] ORDER BY Date ASC) AS ROWNUM
FROM table1
WHERE [STATUS] != 1
AND Date>(
SELECT MIN(Date) AS STARTDATE
FROM table1
WHERE [STATUS] = 1
)
GROUP BY Customer,Date,[Status]
) B
ON
(
A.[Customer] = B.[Customer]
AND A.RowNum = B.RowNum
)
ORDER BY A.Startdate
First you list the rows where Status = 1 and then use CROSS APPLY to get the corresponding minimum Date where the Status is not equal to 1
select s.[Customer],
StartDate = s.[Date],
EndDate = e.[Date]
from Table1 s
cross apply
(
select [Date] = min(e.[Date])
from Table1 e
where e.[Customer] = s.[Customer]
and e.[Date] > s.[Date]
and e.[Status] <> 1
) e
where s.[Status] = 1
order by s.[Customer], s.[Date]
Here is a more efficient way to do this without a self-join.
WITH cte01only AS
( SELECT *, CASE Status WHEN 1 THEN 1 ELSE 0 END AS Status1 FROM table1 ),
cteDifference AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Date, Status1)
- ROW_NUMBER() OVER (PARTITION BY Customer, Status1 ORDER BY Date) AS StatusGroup
FROM cte01only
),
cteGroup AS
(
SELECT Customer, StatusGroup, Status1, MIN(Date) As StartDate
FROM cteDifference
GROUP BY Customer, StatusGroup, Status1
),
cteNextDate AS
(
SELECT Customer, StatusGroup, Status1, StartDate,
LEAD(StartDate, 1, NULL) OVER (PARTITION BY Customer ORDER BY StatusGroup) AS EndDate
FROM cteGroup
)
SELECT Customer, StartDate, EndDate
FROM cteNextDate
WHERE Status1 = 1
ORDER BY Customer, StateDate
The key trick here is the second CTE which uses the difference of two ROW_NUMBER() functions to tag the customer records (with the StatusGroup column) into separate partitions by contiguous runs of records whose status is 1 or not 1. After that they can be grouped according to that tag to get the start dates, and then use the LEAD() function to get the following group's StartDate as the current groupings EndDate.
(There may be a more compact way to express this, but I like to layout each stage as a separate CTE.)
I have 2 tables:
Declare #tbitems TABLE (accntno varchar, saved_amount decimal)
INSERT INTO #tbitems
SELECT 001 , 25
Declare #tbtransact TABLE (idno INT , acctno varchar, amount decimal)
INSERT INTO #tbtransact
SELECT 1 , 001 , 10 UNION ALL
SELECT 2 , 001 , 10 UNION ALL
SELECT 3 , 001 , 10 UNION ALL
SELECT 4 , 001 , 10
tbitems:
accntno | saved_amount (decimal)
--------+-----------------------
001 | 25
tbtransact:
idno | acctno | amount (decimal)
------+---------+-----------------
1 | 001 | 10
2 | 001 | 10
3 | 001 | 10
4 | 001 | 10
How do I get the nearest idno with less than or equal to the saved_amount from tbitems by adding tbtransact amounts ordered by idno (I really don't know how to say it in words).
Anyway based on my table, my expected result should be idno 2 since the nearest under 25 is 20
If I would to do it in java, I would loop through tbtransact then add every row until I go higher than the saved_amount then get the idno before the current one. However I have no idea how to do it in sql.
Expected result is:
idno | acctno | amount
------+---------+-----------------
2 | 001 | 10
This query works for selecting the correct row for a specific account:
SELECT TOP 1
t.idno ,
s.*
FROM dbo.tbitems AS i
INNER JOIN dbo.tbtransact AS t ON i.accntno = t.acctno
CROSS APPLY ( SELECT SUM(l.amount) AS SumAmount
FROM dbo.tbtransact AS l
WHERE l.acctno = t.acctno
AND l.idno <= t.idno
) AS s
WHERE i.accntno = '001' AND s.SumAmount <= i.saved_amount
ORDER BY s.SumAmount DESC;
And this should word accross multipse accounts:
SELECT t.acctno, MAX(idno) AS idno, MAX(s.SumAmount) AS SumAmount
FROM dbo.tbitems AS i
INNER JOIN dbo.tbtransact AS t ON i.accntno = t.acctno
CROSS APPLY ( SELECT SUM(l.amount) AS SumAmount
FROM dbo.tbtransact AS l
WHERE l.acctno = t.acctno
AND l.idno <= t.idno
) AS s
WHERE s.SumAmount <= i.saved_amount
GROUP BY t.acctno
Here is an example using CTE and windowing function:
WITH cte1
AS ( SELECT t.acctno ,
t.amount ,
SUM(t.amount) OVER ( PARTITION BY t.acctno ORDER BY t.acctno, t.idno
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS RunningTotal
FROM dbo.tbtransact AS t
INNER JOIN dbo.tbitems AS i ON t.acctno = i.accntno
),
cte2
AS ( SELECT ROW_NUMBER() OVER ( PARTITION BY cte1.acctno ORDER BY cte1.RunningTotal DESC ) AS rn ,
cte1.acctno ,
cte1.amount ,
cte1.RunningTotal
FROM cte1
)
SELECT cte2.acctno ,
cte2.amount ,
cte2.RunningTotal
FROM cte2
WHERE cte2.rn = 1;
i tried ,it may helps you
Declare #tbitems TABLE (accntno INT , saved_amount decimal)
INSERT INTO #tbitems
SELECT 001 , 25
Declare #tbtransact TABLE (idno INT , acctno INT , amount decimal)
INSERT INTO #tbtransact
SELECT 1 , 001 , 10 UNION ALL
SELECT 2 , 001 , 10 UNION ALL
SELECT 3 , 001 , 10 UNION ALL
SELECT 4 , 001 , 10
SELECT *
FROM (SELECT t.idno,
t.acctno,
t.amount,
CASE
WHEN Sum(saved_amount)
OVER(
partition BY i.accntno
ORDER BY t.idno) <= i.saved_amount THEN i.saved_amount
ELSE 0
END AS Nearest_Saved_amount
FROM #tbtransact t
INNER JOIN #tbitems i
ON i.accntno = t.acctno)Dt
WHERE Dt.Nearest_Saved_amount <> 0
I misunderstood the question the first time. This should do it:
Declare #tbitems TABLE (accntno INT , saved_amount decimal)
INSERT INTO #tbitems
SELECT 001 , 20
Declare #tbtransact TABLE (idno INT , acctno INT , amount decimal)
INSERT INTO #tbtransact
SELECT 1 , 001 , 10 UNION ALL
SELECT 2 , 001 , 10 UNION ALL
SELECT 3 , 001 , 10 UNION ALL
SELECT 4 , 001 , 10
SELECT TOP 1 ttotal.*
FROM #tbtransact t
JOIN (
SELECT idno, acctno, (SELECT SUM(Amount) FROM #tbtransact WHERE acctno = ttemp.acctno and idno <= ttemp.idno) AS Amount
FROM #tbtransact ttemp
WHERE idno <= idno
GROUP BY idno, acctno
) AS ttotal on t.acctno = ttotal.acctno
INNER JOIN #tbitems i ON t.acctno = i.accntno
WHERE ttotal.Amount <= i.saved_amount
ORDER BY ttotal.Amount DESC
consider a table
employee id report_year report_quarter sequencenumber quarter1_wage quarter2_wage
101 2015 1 1 1000 0
101 2015 1 2 2000 0
102 2016 2 1 3000 0
102 2016 2 2 0 4000
The Result of the query must be
Total wages
6000
As in 2015 Employee id 101 with Highest sequence number 2 has 2000 comes under quarter1 as report _quarter is indicating it is 1 need to add take this value and add to the
2016 Employee id 102 with highest sequence number 2 has 4000(quarter2_wage)
as report _quarter is indicating it is 2
I really don't understand why you want to sum this way, but ignoring that you are going to be aggregating across quarters and thus the name "Total Wages" is mis-leading, here is how you accomplish that.
--Assign a row number per employee based off the sequence number.
--This will assign 1 to the highest sequence number for each employee
with cte as(
select
*,
ROW_NUMBER() over (partition by [employee id] order by sequencenumber desc) as rn
from yourTable)
--Sum and add the two quarters for all employees where the row number = 1
--Which is the highest sequence
select
sum(quarter1_wage) + sum(quarter2_wage) as TotalWages
from cte
where rn = 1
Have you tried something like this:
WITH cte0 AS(
SELECT 101 AS employeeid,2015 AS report_year,1 AS report_quarter,1 AS sequencenumber,1000 AS quarter1_wage,0 AS quarter2_wage union all
SELECT 101 ,2015 ,1 ,2 ,2000 ,0 union all
SELECT 102 ,2016 ,2 ,1 ,3000 ,0 union all
SELECT 102 ,2016 ,2 ,2 ,0 ,4000
),
cte1 as(
SELECT employeeid,report_year,report_quarter,MAX(sequencenumber) AS maxseqnum
FROM cte0
GROUP BY employeeid,report_year,report_quarter)
SELECT SUM(quarter1_wage+quarter2_wage) AS [Total wages]
FROM cte0 c0
INNER JOIN cte1 c1
ON c0.report_year = c1.report_year AND c0.report_quarter = c1.report_quarter AND c0.employeeid = c1.employeeid AND c0.sequencenumber = c1.maxseqnum
EDIT: I am using SQL Server 2005
So here's a tricky one. For audit purposes, we need to make 3 attempts to contact a customer. We can make more than 3 attempts to go above and beyond, but audit purposes I need to retrieve the date of the third most recent attempt for each customer.
In most cases, you just need the most recent period, so you can do something like..
SELECT CustID,MAX(AttemptDate) FROM Attempts GROUP BY CustID
.. but that obviously won't work in this scenario.
Say I have a table of attempts that occur which are tied to a customer.
CustID AttemptDate
123 2014-01-02
123 2014-01-05
123 2014-01-06 * retrieve this one
123 2014-01-07
123 2014-01-10
555 2014-02-01
555 2014-02-03
555 2014-02-07 * retrieve this one
555 2014-02-12
555 2014-02-20
Output:
CustID AttemptDate
123 2014-01-06
555 2014-02-07
Any tips for pulling this off?
;WITH t AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY AttemptDate DESC) AS nth_most_recent
FROM MyTable
)
SELECT *
FROM t
WHERE nth_most_recent = 3
The ROW_NUMBER ranking function is your friend here:
WITH cte (CustId, AttemptDate, AttemptNumber) AS (
SELECT
CustId,
AttemptDate,
ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY AttemptDate DESC) AS AttemptNumber
FROM Attempts
)
SELECT
CustId,
AttemptDate
FROM cte
WHERE AttemptNumber = 3
Alternatively, if the common table expression syntax is causing problems, you could use a subquery:
SELECT
CustId,
AttemptDate
FROM (
SELECT
CustId,
AttemptDate,
ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY AttemptDate DESC) AS AttemptNumber
FROM Attempts
) sq
WHERE AttemptNumber = 3