Related
I have this table. With case#, Linenumber and code#.
case# Linenumber Code#
99L1HV 1 1510
99L1HV 2 4320
99PX58 1 1510
99PX58 2 4320
99PX58 3 4500
99PX59 1 1510
99PX59 2 918
99PX59 3 4320
How can I get the records with the last LineNumber per case# where code = 4320
The output should be like this
case# Linenumber Code
99L1HV 2 4320
99PX59 3 4320
Using ROW_NUMBER to get a number that's in the opposite order of the linenumber per case#.
Then the last lines will have RN = 1
SELECT [case#], Linenumber, [Code#]
FROM
(
SELECT [case#], Linenumber, [Code#],
ROW_NUMBER() OVER (PARTITION BY [case#] ORDER BY Linenumber DESC) AS RN
FROM yourtable
) q
WHERE RN = 1
AND [Code#] = 4320
ORDER BY [case#];
Or the more concise version.
Using a TOP 1 WITH TIES in combination with an ORDER BY ROW_NUMBER.
SELECT *
FROM
(
SELECT TOP 1 WITH TIES [case#], Linenumber, [Code#]
FROM yourtable
ORDER BY ROW_NUMBER() OVER (PARTITION BY [case#] ORDER BY Linenumber DESC)
) q
WHERE [Code#] = 4320
ORDER BY [case#];
cte is to generate a running number by case#. rn = 1 will be the last row for each case#
; with cte as
(
select *, rn = row_number() over (partition by [case#] order by linenumber desc)
from yourtable
)
select *
from cte
where rn = 1
and [code#] = 4320
declare #t table (
CaseNumber varchar(10),
LineNumber int,
CodeNumber int
);
-- Filling the table with data, skipped
select t.*
from #t t
where t.CodeNumber = 4320
and not exists (
select 0 from #t x
where x.CaseNumber = t.CaseNumber
and x.LineNumber > t.LineNumber
);
with cte as
(select case#, max(linenumber)
from source_table
group by case#)
select t1.*
from source_table t1 inner join cte t2
on t1.case# = t2.case# and t1.linenumber = t2.linenumber
where t1.Code# = 4320
Is it possible to make this in sql:
Have table with records:
ID LaborID OrderNr OrderStatusID OrderStatusDate
12990 3731573 OPT1814378 2 2018-05-28 09:35:30.123
13105 230687389 OPT1814378 1 2018-05-29 10:32:14.850
13106 230687389 OPT1814378 2 2018-05-29 10:52:14.403
13123 230480202 OPT1814378 1 2018-05-29 13:18:05.233
13130 230480202 OPT1814378 0 2018-05-29 13:29:17.360
12837 3731573 OPT1814089 2 2018-05-25 20:28:24.817
12906 10138504 OPT1814089 1 2018-05-26 10:41:18.680
12909 10138504 OPT1814089 2 2018-05-26 10:57:40.733
12913 10138504 OPT1814089 1 2018-05-26 11:41:48.387
12920 10138504 OPT1814089 0 2018-05-26 12:15:48.590
where
OrderStatusID
0 - End
1 - Begin
2 - pause
Need calculate working time from begin to pause (1->2) or from begin to end (1->0).
My problem is that there are some conditions that I have to adhere to:
If first record is 2 then ignore
Work begin always with 1
But can have more pause (1->2)
The last work end record everytime with 0
The result in this case will be:
OPT1814378 230687389 00:20:00
OPT1814378 230480202 00:11:12
OPT1814089 10138504 00:16:12
OPT1814089 10138504 00:34:00
Hopefully this is not that ugly.
; with
cte as
(
-- CTE for generating a sequence no
select *, rn = row_number() over (partition by OrderNr
order by OrderStatusDate)
from #table
),
cte2 as
(
-- Clean up invalid any rows and regenerate new sequence no
select ID, LaborID, OrderNr, OrderStatusID, OrderStatusDate,
rn = row_number() over (partition by OrderNr
order by OrderStatusDate)
from cte
where (rn = 1 and OrderStatusID = 1)
or rn >= 2
)
select OrderNr, LaborID,
convert(varchar(10),
dateadd(second,
datediff(second,
min(OrderStatusDate),
max(OrderStatusDate)),
0),
108)
from cte2
group by OrderNr,
LaborID,
(rn - 1) / 2
(rn - 1) / 2 will gives the value 0, 0, 1, 1, 2, 2 etc for grouping the rows two by two.
This one also works
;WITH CTE
AS (
SELECT row_number() OVER ( PARTITION BY ordernr ORDER BY id ) RN ,* FROM test_ti
)
,cte2
AS (
SELECT *
FROM cte c1
WHERE NOT EXISTS (
SELECT *
FROM cte c2
WHERE c1.id = c2.id
AND c2.rn = 1
AND c2.orderstatusid = 2
)
)
SELECT OrderNr
,LaborId
,TimeInterval
FROM ( SELECT DateDiff(MI, TIME, NxtTm) TimeInterval ,*
FROM (
SELECT * ,lead(TIME) OVER ( ORDER BY id ) NxtTm
FROM cte2
) x
WHERE orderstatusid <> 0
) y
WHERE orderstatusid = 1
Using SQL Server, I have...
AccDocumentItems Table:
SLId DL1Id DL2Id Debit Credit CurId ExchangeRate Cnt
------------------------------------------------------------------------------
S1 D1 D4 2000 0 1 1000 2
S1 D1 D4 0 6000 1 1500 4
S1 D1 D4 6000 0 1 1200 5
S2 D2 D4 4000 0 2 1000 4
S2 D2 D4 0 2000 2 1000 2
S2 D2 D4 3000 0 2 1500 2
I am trying to write a query in sql that group by CurId then substract Cnt column that has debit greater than 0 from Cnt Column that has Debit 0,for example row 1 to 3 has CurId 1 and row 1 has Debit greater than zero,then we have (2-4+5)=3 and row 4 to 6 has CurId 2 then we have (4-2+2)=4 finally I want sum of them 3*Last ExchangeRate in ExchangeRates Table, and 4*Last ExchangeRate in ExchangeRates Table, then sum of (3*Last ExchangeRate+4*Last ExchangeRate).
ExchangeRates Table:
CurrencyId EffectiveDate ExchangeRate
------------------------------------------------
1 2016-1-1 1000
2 2016-1-2 1200
2 2016-1-3 2000
1 2016-1-4 1500
result=(3*Last ExchangeRate+4*Last ExchangeRate)-((sum of Debit)-(sum
of Credit))
in this example Last ExchangeRate for CurrencyId 1 is 1500, and Last ExchangeRate for CurrencyId 2 is 2000 finally I want this result
result=(3*1500+4*2000)-(15000-8000)
This solution is based on your calculations and works only with 2 CurId's.
declare #cur_1 int = 1
declare #cur_2 int = 2
;with AccDocumentItems as (
select
*
from
(values
('S1','D1','D4',2000,0,1,1000,2)
,('S1','D1','D4',0,6000,1,1500,4)
,('S1','D1','D4',6000,0,1,1200,5)
,('S2','D2','D4',4000,0,2,1000,4)
,('S2','D2','D4',0,2000,2,1000,2)
,('S2','D2','D4',3000,0,2,1500,2)
) t (SLId, DL1Id, DL2Id, Debit, Credit, CurId, ExRate, Cnt)
)
, ExchangeRates as (
select
*
from
(values
(1,'2016-1-1',1000)
,(2,'2016-1-2',1200)
,(2,'2016-1-3',2000)
,(1,'2016-1-4',1500)
) t (CurrencyId, EffectiveDate, ParityRate)
)
select
sum(t.cnt * q.ParityRate) - sum(diff)
from
(
select
CurId, diff = sum(Debit) - sum(Credit), cnt = sum(cnt * case when Debit = 0 then -1 else 1 end)
from
AccDocumentItems
where
CurId in (#cur_1, #cur_2)
group by CurId
) t
join (
select
top 1 with ties *
from
ExchangeRates
order by row_number() over (partition by CurrencyId order by EffectiveDate desc)
) q on t.CurId = q.CurrencyId
This solution works for All CurId's.
Declare #Result int
Declare #DeCr int
Declare #Cur int
Set #DeCr = (
Select SUM(Debit)-SUM(Credit)
From dbo.AccDocumentItems
)
Set #Cur =
(
Select Sum(ParityRate * Zarib)
From
(
Select ExchangeRates.CurrencyId as cuur,ParityRate
From
(
Select Max(EffectiveDate) As MaxDate,CurrencyId
From dbo.ExchangeRates
Group by CurrencyId
)As Table1
left join
dbo.ExchangeRates
ON table1.currencyid = ExchangeRates.CurrencyId
And Table1.MaxDate = EffectiveDate
) As Table3
inner join
(
Select Curid
, sum(cnt*signs) As Zarib
From
(
Select CurId
, Cnt
, Case
When Debit = 0 Then -1
Else 1
End As Signs
From dbo.AccDocumentItems
) As Table2
Group by Curid
) As Table4
On Table3.cuur = Table4.Curid
)
Select #Cur - #DeCr
Declare #Result int
Declare #DeCr int
Declare #Cur int
Set #DeCr = (
Select SUM(Debit)-SUM(Credit)
From dbo.AccDocumentItems
)
Set #Cur =
(
Select Sum(ParityRate * Zarib)
From
(
Select ExchangeRates.CurrencyId as cuur,ParityRate
From
(
Select Max(EffectiveDate) As MaxDate,CurrencyId
From dbo.ExchangeRates
Group by CurrencyId
)As Table1
left join
dbo.ExchangeRates
ON table1.currencyid = ExchangeRates.CurrencyId
And Table1.MaxDate = EffectiveDate
) As Table3
inner join
(
Select Curid
, sum(cnt*signs) As Zarib
From
(
Select CurId
, Cnt
, Case
When Debit = 0 Then -1
Else 1
End As Signs
From dbo.AccDocumentItems
) As Table2
Group by Curid
) As Table4
On Table3.cuur = Table4.Curid
)
set #result = #Cur - #DeCr
Select #result
Needs some help on the following:
Table #Data contains the Opening and Closing Stock for a product over 5 days
Table #BackData contains some post dated transactions
How can i Update the table #Data with a Running Total including a carry forward
CREATE TABLE #Data (
Prod VARCHAR(20)
,SDate DATE
,OStock INT
,CStock INT
)
CREATE TABLE #BackData (
Prod VARCHAR(20)
,SDate DATE
,CStock INT
)
INSERT INTO #Data
SELECT 'p1', '2016-06-06', 10, 10
UNION ALL
SELECT 'p1', '2016-06-07', 10, 14
UNION ALL
SELECT 'p1', '2016-06-08', 14, 13
UNION ALL
SELECT 'p1', '2016-06-09', 13, 13
UNION ALL
SELECT 'p1', '2016-06-10', 13, 11
INSERT INTO #BackData
SELECT 'p1', '2016-06-06', 2
UNION ALL
SELECT 'p1', '2016-06-07', 4
UNION ALL
SELECT 'p1', '2016-06-09', -1
UNION ALL
SELECT 'p1', '2016-06-10', -2
DROP TABLE #Data
DROP TABLE #BackData
Desired Output :
Prod| SDate |OStock |CStock|
p1 |2016-06-06 |10 |12 |
p1 |2016-06-07 |12 |16 |
p1 |2016-06-08 |16 |16 |
p1 |2016-06-09 |16 |15 |
p1 |2016-06-10 |15 |13 |
EDIT
This is what i had managed to write before i got the answer, using two updates because the actual table had too many columns to use in a single query.
UPDATE D
SET D.CStock = FL.NewCStock
FROM #Data D
INNER JOIN (
SELECT DT.Prod
,DT.SDate
,SUM(IIF(RwNm = 1, DT.CStock, 0) + ISNULL(BD.CStock, 0)) OVER (
PARTITION BY DT.Prod ORDER BY DT.SDate ROWS UNBOUNDED PRECEDING
) NewCStock
FROM (
SELECT Prod
,SDate
,CStock
,ROW_NUMBER() OVER (
PARTITION BY Prod ORDER BY SDate
) AS RwNm
FROM #Data
) DT
LEFT JOIN #BackData BD ON DT.Prod = DT.Prod
AND BD.SDate = DT.SDate
) FL ON D.Prod = FL.Prod
AND D.SDate = FL.SDate
UPDATE D
SET D.OStock = PV.NewOStock
FROM #Data D
INNER JOIN (
SELECT Prod
,SDate
,ISNULL(LAG(CStock) OVER (
PARTITION BY Prod ORDER BY SDate
), CStock) AS NewOStock
FROM #Data
) PV ON D.Prod = PV.Prod
AND D.SDate = PV.SDate
You can use the following query to UPDATE:
;WITH ToUpdate AS (
SELECT d1.OStock, d1.CStock,
COALESCE(LAG(d2.CStock2) OVER (PARTITION BY d2.Prod
ORDER BY d2.SDate),
d1.OStock) AS OStock2,
d2.CStock2
FROM #Data AS d1
JOIN (
SELECT d.Prod, d.SDate, d.OStock, d.CStock,
COALESCE(t.newCStock,
LAG(t.newCStock) OVER (PARTITION BY d.Prod
ORDER BY d.SDate)) AS CStock2
FROM #Data AS d
LEFT JOIN (
SELECT bd.Prod, bd.SDate,
drn.CStock + SUM(bd.CStock) OVER (PARTITION BY bd.Prod
ORDER BY bd.SDate) AS newCStock
FROM #BackData AS bd
INNER JOIN (
SELECT Prod, CStock,
ROW_NUMBER() OVER (PARTITION BY Prod ORDER BY SDate) AS rn
FROM #Data
) AS drn ON bd.Prod = drn.Prod AND drn.rn = 1
) AS t ON t.Prod = d.Prod AND t.SDate = d.SDate
) AS d2 ON d1.Prod = d2.Prod AND d1.SDate= d2.SDate
)
UPDATE ToUpdate
SET OStock = OStock2,
CStock = CStock2
This looks awfully convoluted, but I couldn't think of anything simpler.
Demo here
You can rebuild values in #Data table with the help of recursive CTE:
;WITH cte AS (
SELECT top 1 d.Prod,
d.SDate,
d.OStock,
d.OStock + b.CStock as CStock
FROM #Data d
LEFT JOIN #BackData b
ON b.Prod = d.Prod and b.SDate = d.SDate
ORDER BY d.SDate ASC
UNION ALL
SELECT c.Prod,
DATEADD(day,1,c.SDate),
c.CStock,
c.CStock + ISNULL(b.CStock,0)
FROM cte c
INNER JOIN #Data d
ON d.Prod = c.Prod AND d.SDate = DATEADD(day,1,c.SDate)
OUTER APPLY (SELECT CStock FROM #BackData b WHERE b.Prod = d.Prod and b.SDate = d.SDate) as b
)
SELECT *
FROM cte
Output:
Prod SDate OStock CStock
-------------------- ---------- ----------- -----------
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
To update #Data:
UPDATE d
SET OStock = c.OStock, CStock = c.CStock
FROM #Data d
INNER JOIN cte c
ON c.Prod = d.Prod AND c.SDate = d.SDate
Shouldn't the result be like :
Prod SDate OStock CStock
p1 2016-06-06 10 12
p1 2016-06-07 12 20 (#Data CStock 14 + #BakData 2 + 4)
p1 2016-06-08 20 19 (#Data CStock 13 + #BakData 2 + 4)
p1 2016-06-09 19 18 (#Data CStock 13 + #BakData 2 + 4 - 1)
p1 2016-06-10 18 14 (#Data CStock 11 + #BakData 2 + 4 - 1 -2)
This query will produce the above result
update d
set OStock = d.OStock + a.OAdj,
CStock = d.CStock + a.CAdj
from #Data d
cross apply
(
select OAdj = sum(case when Oflag = 1 then x.CStock else 0 end),
CAdj = sum(x.CStock)
from
(
select *, Oflag = case when x.SDate = d.SDate then 0 else 1 end
from #BackData x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) x
) a
Based on your expected output, it seems that you are re-calculating the daily Opening / Closing balance based on the figure from 2016-06-06
Here is a solution that will gives you your expected output.
; with
cte as
(
select Prod, SDate, OStock, CStock,
rn = row_number() over (partition by Prod order by SDate)
from #Data
),
adj as
(
select Prod, SDate, CStock
from cte
where rn = 1
union all
select Prod, SDate, CStock
from #BackData
)
update d
set OStock = coalesce(o.OStock, d.OStock),
CStock = c.CStock
from #Data d
cross apply
(
select OStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate < d.SDate
) o
cross apply
(
select CStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) c
Result :
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
I need to find customers who have made identical orders. (Using T-SQL)
Order
OrderID Customerer
1 2
2 5
3 6
4 2
5 4
6 6
7 8
OrderLine
OrderLineID OrderID OrderDate OrderType Quantity Reference
1 1 01/01/2011 1 1 Coca Cola
2 1 01/01/2011 1 3 Tea
3 2 02/02/2011 2 1 Coffee
4 2 02/02/2011 2 2 Solo
5 2 03/02/2011 1 1 Soda
6 3 03/02/2011 1 3 Tea
7 3 03/02/2011 1 1 Coca Cola
8 4 05/06/2011 1 1 Beer
9 5 06/06/2011 2 1 Tea
10 5 06/06/2011 2 1 Coca Cola
11 6 07/07/2011 1 1 Coffee
12 6 07/07/2011 1 2 Solo
13 6 07/07/2011 1 1 Soda
14 6 07/07/2011 1 1 Beer
15 7 08/08/2011 1 1 Beer
Here orders with OrderID 1 and 3 are considered to be identical because the number for orderlines, "Quantity" and "Reference" are identical on both orders. Meaning that customer 2 and 6 have placed identical orders.
Order 5 are not identical to order 1 and 3 because Quantity differ.
Order 2 are not identical to order 6 because orderlines differ.
Order 4 and 7 are also identical.
I am searching for a ressult like this:
IdenticalOrders
OrderID CustomeerID
1 2
3 6
4 2
7 8
It seems like an easy task, but I just can't understand where to start.
(I am still new to t-sql :-) )
Here's one way.
SELECT O1.OrderID ,
O1.Customer ,
O2.OrderID ,
O2.Customer
FROM [Order] O1
JOIN [Order] O2 ON O1.OrderID < O2.OrderID
AND O1.Customer <> O2.Customer
WHERE NOT EXISTS ( SELECT Quantity ,
Reference
FROM OrderLine
WHERE O1.OrderID = OrderLine.OrderID
EXCEPT
SELECT Quantity ,
Reference
FROM OrderLine
WHERE O2.OrderID = OrderLine.OrderID )
AND NOT EXISTS ( SELECT Quantity ,
Reference
FROM OrderLine
WHERE O2.OrderID = OrderLine.OrderID
EXCEPT
SELECT Quantity ,
Reference
FROM OrderLine
WHERE O1.OrderID = OrderLine.OrderID )
You can also use XML PATH to simulate GROUP_CONCAT then JOIN the two result sets
DECLARE #T TABLE
(
OrderId INT PRIMARY KEY,
Customer INT ,
complete_order VARCHAR(MAX)
)
INSERT INTO #T
SELECT *
FROM [Order] O
CROSS APPLY ( SELECT CAST(Quantity AS VARCHAR(30))
+ '~' + Reference + '~~'
FROM OrderLine OL
WHERE OL.OrderID = O.OrderID
ORDER BY Reference ,
Quantity
FOR
XML PATH('')
) T ( complete_order )
SELECT T1.OrderId,
T1.Customer
FROM #T T1
WHERE EXISTS ( SELECT *
FROM #T T2
WHERE T1.Customer <> T2.Customer
AND T1.OrderId <> T2.OrderId
AND T1.complete_order = T2.complete_order )
This is an extension of Martin's second suggestion. This will show all matching combinations without any repetitions.
;With FmtOL(customer, orderid, complete_order) as
(
SELECT customer, orderid, complete_order
FROM Order O
cross apply ( SELECT CAST(Quantity AS VARCHAR(30))
+ '~' + Reference + '~~'
FROM OrderLine OL
WHERE OL.OrderID = O.OrderID
ORDER BY Reference ,
Quantity
FOR
XML PATH('')
) T ( complete_order )
)
SELECT T1.OrderId,
T1.Customer,
STUFF(C1.a, 1, 2, '') as [SameAs]
FROM FmtOL T1
Cross apply ( SELECT '; ' + 'Customer ' + Cast(T2.Customer as varchar(30))
+ '''s order ' + Cast(T2.OrderID as varchar(30))
FROM FmtOL T2
WHERE T1.Customer < T2.Customer
AND T1.OrderId < T2.OrderId
AND T1.complete_order = T2.complete_order
order by ';' + Cast(T2.Customer as varchar(30))
+ '''s order ' + Cast(T2.OrderID as varchar(30))
, t2.orderid
for xml path('')
) C1 (a)
where C1.a is not null
Results should look like this:
OrderId Customer SameAs
1 2 Customer 6's order 3
4 2 Customer 8's order 7
Here's the most simple approach.
-- sample table
create table x
(
LineId int identity(1, 1)
,InvoiceFk int
,ProductFk int
,Quantity int
)
-- sample data
insert into x
(InvoiceFk, ProductFk, Quantity) values
(11, 1, 1)
,(11, 2, 1)
,(11, 3, 1)
,(12, 1, 2)
,(12, 2, 2)
,(12, 3, 2)
,(13, 1, 3)
,(13, 2, 3)
,(13, 3, 3)
-- your order, probably from a parameter
declare #order table
(
InvoiceFk int
,ProductFk int
,Quantity int
)
insert into #order
(InvoiceFk, ProductFk, Quantity) values
(14, 1, 1) -- duplicate invoice 11
,(14, 2, 1)
,(14, 3, 1)
-- your order unique checksum
declare #orderCheck int
select #orderCheck = checksum_agg(checksum(ProductFk, Quantity))
from #order
-- test your order in existing data
declare #match int
select #match =
(
select TOP 1 InvoiceFk from
(
select
InvoiceFk
,checksum_agg(Col1) as Col2
from
(
select
InvoiceFk
,checksum(productfk, quantity) as Col1
from x
) as T1
group by
InvoiceFk
) as T2
where
T2.Col2 = #orderCheck
)
-- evaluate if your order is unique or not
if (#match is not null)
begin
print 'Identical to invoice: ' + Str(#match);
end
else
begin
print 'Order is unique';
end
-- clean up sample table
drop table x
Best of luck!