How to get first value from first row and last value from last row in SQL Server - sql

I have a table in SQL Server as below
+---+-------------+-------------+-------------+
|Id | FromCity | ToCity | RequestId |
+---+-------------+-------------+-------------+
| 1 | Mysore | Atlanta | 12 |
+---+-------------+-------------+-------------+
| 2 | Atlanta | Singapore | 12 |
+---+-------------+-------------+-------------+
| 3 | Singapore | Pakistan | 12 |
+---+-------------+-------------+-------------+
| 4 | Pakistan | Myscot | 12 |
+---+-------------+-------------+-------------+
| 5 | Rome | Singapore | 13 |
+---+-------------+-------------+-------------+
Here, I am trying to get a value as From and To Cities (Round Trip Data) (i.e. Mysore - > Myscot for the RequestId =12). Ho to get this value?
When I pass RequestId=12, I should get the value as Mysore -> Myscot
I Tried as below:
SELECT MIN(FromCity) [From],
MAX(ToCity) [To]
FROM MyTable
WHERE RequestId = 12
But I'm getting Mysore -> Singapore (based on string MIN and MAX).

Check This :
SELECT M.FromCity [From],
M2.ToCity [To]
FROM #MyTable M
Inner join (select Min(ID) min ,Max(ID) max from #MyTable M2 WHERE M2.RequestId = 12 )
A on A.Min =ID
Inner join #MyTable M2 on M2.ID=A.Max
Output :

SELECT RequestId,
f.FromCity [From],
t.ToCity [To]
FROM MyTable t
CROSS APPLY (
SELECT TOP (1) FromCity
FROM MyTable
WHERE RequestId = t.RequestId
ORDER BY Id ASC
) f
CROSS APPLY (
SELECT TOP (1) ToCity
FROM MyTable
WHERE RequestId = t.RequestId
ORDER BY Id DESC
) t
WHERE RequestId = 12

The only logic I see is using the Id from your table and do something like this. Using CTE you will find the MIN and MAX id per request, that means from city - to city.
And after that you join your table to the CTE to find the actual values.
declare #tbl as table
([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;
INSERT INTO #tbl
([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
(1, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
(2, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
(3, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
(4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
(5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
(6, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
(7, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13);
;with cte as (
select
MIN(Id) as [start]
,MAX(Id) as [end]
,RequestId
from #tbl
group by requestID
)
select
t1.FromCity
,t1.[Date Created]
,t2.ToCity
,t2.[Date Created]
from cte
inner join #tbl t1
on t1.Id = cte.[start]
and t1.RequestId = cte.RequestId
inner join #tbl t2
on t2.Id = cte.[end]
and t2.RequestId = cte.RequestId
Update: based on #Panagiotis Kanavos comment you can simplify the query like this
;with cte as (
select
MIN(Id) as [start]
,MAX(Id) as [end]
from #tbl
where RequestId = 12 ---> here you can use a variable containing the requestID
)
select
t1.FromCity
--,t1.[Date Created]
,t2.ToCity
--,t2.[Date Created]
from cte
inner join #tbl t1
on t1.Id = cte.[start]
inner join #tbl t2
on t2.Id = cte.[end]

If Id in main table is used to describe travel order then something like this will work:
SELECT startLocation.FromCity [From], endLocation.ToCity AS [To]
FROM (
SELECT MIN(Id) AS StartLocationId, MAX(Id) AS EndLocationId
FROM MyTable
WHERE RequestId = 12
) AS a
INNER JOIN MyTable AS startLocation ON a.StartLocationId = startLocation.Id
INNER JOIN MyTable AS endLocation ON a.EndLocationId = endLocation.Id
This is a example of solution for situation when ids are just ids and don`t match travel order:
declare #tbl as table
([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;
INSERT INTO #tbl
([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
(19, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
(22, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
(1, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
(4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
(5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
(0, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
(-1, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13)
;
select * from #tbl
declare #Id int = 12
declare #FromStart nvarchar(255), #ToStart nvarchar(255)
declare #StartResult nvarchar(255), #ToResult nvarchar(255)
declare #StartResultFound bit = 0, #ToResultFound bit = 0
-- select random starting point
select #FromStart = [FromCity], #ToStart = [ToCity] from #tbl where [RequestId] = #Id
ORDER BY NEWID()
select #FromStart, #ToStart
while (#StartResultFound = 0)
begin
if exists (select top 1 1 from #tbl where [RequestId] = #Id and [ToCity] = #FromStart)
begin
select top 1 #FromStart = [FromCity] from #tbl where [RequestId] = #Id and [ToCity] = #FromStart
end
else
begin
set #StartResultFound = 1
set #StartResult = #FromStart
end
end
while (#ToResultFound = 0)
begin
if exists (select top 1 1 from #tbl where [RequestId] = #Id and [FromCity] = #ToStart)
begin
select top 1 #ToStart = [ToCity] from #tbl where [RequestId] = #Id and [FromCity] = #ToStart
end
else
begin
set #ToResultFound = 1
set #ToResult = #ToStart
end
end
select #StartResult, #ToResult

maybe this is whar you need
DECLARE
#t TABLE (
ID INT
, FromCity VARCHAR(250)
, ToCity VARCHAR(250)
, RequestId INT
)
INSERT INTO #t VALUES
(1,'Mysore','Atlanta',12)
,(2,'Atlanta','Singapore',12)
,(3,'Singapore','Pakistan',12)
,(4,'Pakistan','Myscot',12)
,(5,'Rome','Singapore',13)
SELECT DISTINCT
ISNULL(FromCity, ISNULL(NextCity, PreCity) ) FromCity
, ISNULL(ToCity, ISNULL(NextCity2, PreCity2) ) FromCity
FROM (
SELECT
CASE WHEN RN = 1 THEN FromCity END FromCity
, CASE WHEN RN = CNT THEN ToCity END ToCity
, LEAD(CASE WHEN RN = 1 THEN FromCity END) OVER(PARTITION BY RequestId ORDER BY ID) NextCity
, LEAD(CASE WHEN RN = CNT THEN ToCity END) OVER(PARTITION BY RequestId ORDER BY ID) NextCity2
, LAG(CASE WHEN RN = 1 THEN FromCity END) OVER(PARTITION BY RequestId ORDER BY ID) PreCity
, LAG(CASE WHEN RN = CNT THEN ToCity END) OVER(PARTITION BY RequestId ORDER BY ID) PreCity2
FROM (
SELECT
*, ROW_NUMBER() OVER(PARTITION BY RequestId ORDER BY ID) RN
, COUNT(ToCity) OVER(PARTITION BY RequestId) CNT
FROM #t
) D
WHERE
RN = 1 OR RN = CNT
) C

A recursive version, not depending on Ids order. The idea is to build the biggest chain of trip connected by To / From cities.
WITH cte1 AS (
-- start with all trips as 1 hop chain
SELECT [FromCity], [ToCity], 1 AS HOP
FROM Mytable
WHERE REQUESTID = 12
UNION ALL
-- recursively add one hop if we find a trip ending in start city of the chain
SELECT T.[FromCity], cte1.[ToCity], cte1.HOP + 1
FROM cte1
JOIN Mytable t
ON t.[ToCity] = cte1.[FromCity]
WHERE t.REQUESTID = 12
)
, cte2 AS (
-- order by number of hops
SELECT [FromCity], [ToCity], ROW_NUMBER() OVER (ORDER BY HOP DESC) AS N
FROM cte1
)
-- choose the chain with the more hops
SELECT [FromCity], [ToCity]
FROM cte2
WHERE N = 1

try this code
SELECT MIN(Id) [From],
MAX(Id) [To]
FROM MyTable
WHERE RequestId = 12

Related

Ranking functions and Joins

I have the following tables.
Order_det
Ord_num
item_code
Unit_sales_price
1111
1
50
1111
2
40
1111
3
30
1111
4
20
1111
5
10
2222
3
30
Pick_det
Ord_num
Shipment_num
Item_code
Qty_to_pick
Qty_picked
1111
1
1
100
100
1111
2
1
100
100
1111
3
2
100
100
2222
3
3
200
200
I want the table as follows,
Ord_num
Shipment_num
Item_code
Qty_to_pick
Qty_picked
Unit_sales_price
Total_price (Unit_sales_price*Qty_picked)
1111
3
2
100
100
40
4000
2222
3
3
200
200
30
6000
With the help of this community, I found a very similar answer i.e,
Link to that answer, Similar question
select *
from
(
select t1.*, max(shipment_num) over (partition by ord_num) as orders_max_ship_num
from pick_det t1
) with_max
where shipment_num = orders_max_ship_num
order by ord_num, item_code;
My question is,
where do I join the Order_det table to get the Unit_sales_price value to the already retrieved max shipment_num rows from pick_det table?
Im late to the party, as I typed everything up and made sure it ran correctly
if OBJECT_ID('tempdb..#Order_det') IS NOT NULL DROP TABLE #Order_det;
if OBJECT_ID('tempdb..#Pick_det') IS NOT NULL DROP TABLE #Pick_det;
CREATE TABLE #Order_det (Ord_num INT, item_code INT, Unit_sales_price INT);
CREATE TABLE #Pick_det(Ord_num INT, Shipment_num INT, Item_code INT, Qty_to_pick INT, Qty_picked INT);
INSERT INTO #Order_det (Ord_num, item_code, Unit_sales_price)
VALUES
(1111, 1, 50),
(1111, 2, 40),
(1111, 3, 30),
(1111, 4, 20),
(1111, 5, 10),
(2222, 3, 30)
INSERT INTO #Pick_det (Ord_num, Shipment_num, Item_code, Qty_to_pick, Qty_picked)
VALUES
(1111, 1, 1, 100, 100),
(1111, 2, 1, 100, 100),
(1111, 3, 2, 100, 100),
(2222, 3, 3, 200, 200)
SELECT
OrderDet.Ord_num
, PickList.Shipment_Num
, OrderDet.Item_code
, PickList.Qty_to_pick
, PickList.Qty_picked
, OrderDet.Unit_sales_price
, OrderDet.Unit_sales_price * PickList.Qty_picked AS Total_price
FROM
(
SELECT
Ord_num
, MAX(Shipment_num) OVER (PARTITION BY ord_num) AS MaxShipment_Num--
, Shipment_num
, Item_code
, Qty_to_pick
, Qty_picked
FROM #Pick_det
) AS PickList
INNER JOIN #Order_det AS OrderDet
ON OrderDet.Ord_num = PickList.Ord_num
AND OrderDet.item_code = PickList.Item_code
and PickList.Shipment_num = PickList.MaxShipment_Num
You can simply base a query on yours:
with s as
(
select *
from
(
select t1.*, max(shipment_num) over (partition by ord_num) as orders_max_ship_num
from pick_det t1
) with_max
where shipment_num = orders_max_ship_num
)
select
s.ord_num, s.shipment_num, s.item_code, s.qty_to_pick, s.qty_picked,
od.unit_sales_price, od.unit_sales_price * s.qty_picked as total_price
from s
join order_det od on od.ord_num = s.ord_num and od.item_code = s.item_code
order by s.ord_num, s.item_code;
Or you apply the join right away:
select
s.ord_num, s.shipment_num, s.item_code, s.qty_to_pick, s.qty_picked,
od.unit_sales_price, od.unit_sales_price * s.qty_picked as total_price
from
(
select t1.*, max(shipment_num) over (partition by ord_num) as orders_max_ship_num
from pick_det t1
) s
join order_det od on od.ord_num = s.ord_num and od.item_code = s.item_code
where s.shipment_num = s.orders_max_ship_num
order by s.ord_num, s.item_code;
Another simple technique you could use is by applying analytic function - Dense_Rank which is a window function that assigns a rank to each row within a partition of a result set
I am trying to rank by shipment_num in descending order and then just JOINing on the common column. I have used CTE and sub-query as well:
With temp AS(Select * from (SELECT a.*, dense_rank() OVER (PARTITION BY ord_num order by shipment_num desc) rnk
from Pick_det a) t where rnk = 1)
Select temp.Ord_num, temp.Shipment_num, temp.item_code, temp.Qty_to_pick, temp.Qty_picked,
temp.qty_to_pick * Order_det.Unit_sales_price total_price
from temp JOIN Order_det on temp.ord_num = Order_det.ord_num
AND temp.item_code = Order_det.item_code;
Your Sub-query would look something like this:
Select temp.Ord_num, temp.Shipment_num, temp.Item_code, temp.Qty_to_Pick, temp.Qty_picked,
temp.qty_to_pick * Order_det.Unit_sales_price total_price
from
(SELECT a.*, dense_rank() OVER (PARTITION BY ord_num order by shipment_num desc) rnk
from Pick_det a) temp INNER JOIN Order_det on temp.ord_num = Order_det.ord_num
AND temp.item_code = Order_det.item_code
AND temp.rnk = 1;
If you want to learn about dense_rank function, here is the link
Here is the SQL Fiddle

Pivot query is returning all the values in T-SQL

I am having a requirement that I want to build a pivot query for my table which is shown in screen shot.
This is my table
I want to make the rows values into columns.
My try:
SELECT rno, NO,Description,CarNo,ID from
(
select row_number()over(partition by columnname order by rno)rno, columnname,value
from mytable
group by rno, columnname,value
) x
pivot
(
max(value)
for columnname in (NO,Description,CarNo,ID)
) p
Actual Output:
Expected Output:
NO | Description | CradNo | ID
---------------------------------------------
Part1 | desc1 | Card1 | 1
Part2 | desc2 | Card1 | 1
You can use this.
DECLARE #mytable TABLE(columnname VARCHAR(20), value VARCHAR(10), rno INT)
INSERT INTO #mytable
VALUES
('ID', '1', 1),
('NO', 'Part1', 1),
('NO', 'Part2', 1),
('Description', 'desc1', 1),
('Description', 'desc2', 1),
('CarNo', 'car1', 1)
;WITH CTE AS
(SELECT * FROM
(SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY columnname Order BY rno, value)
FROM #mytable) SRC
PIVOT ( MAX(value) FOR columnName IN ([ID], [NO], [Description], [CarNo]) ) PVT
)
SELECT
ISNULL( T1.NO, T2.NO) NO
, ISNULL( T1.Description, T2.Description) Description
, ISNULL( T1.CarNo, T2.CarNo) CarNo
, ISNULL( T1.ID, T2.ID) ID
FROM CTE T1 OUTER APPLY ( SELECT TOP 1 * FROM CTE WHERE CTE.RN < T1.RN ) T2
Result:
NO Description CarNo ID
---------- ----------- ---------- ----------
Part1 desc1 car1 1
Part2 desc2 car1 1

Split set of values into 5 groups each group should have sum(count) evenly

SQL Server to split set of values into 5 groups each group should have sum(count) evenly distributed.
Table contains only 2 columns rid and count.
create table t1(rid int, count int)
insert into t1
values (1, 4567), (2, 3256), (3, 5678), (4, 934),
(5, 1099), (6, 3990), (7, 780), (8, 6784),
(9, 7854), (10, 435), (11, 3455), (12, 4897),
(13, 8849), (14, 1019), (15, 2387)
Actual table is
rid count
---------
1 4567
2 3256
3 5678
4 934
5 1099
6 3990
7 780
8 6784
9 7854
10 435
11 3455
12 4897
13 8849
14 1019
15 2387
I need to divide the values into into 5 groups dynamically, each group should have sum(count) evenly distributed
The sum of the columns is equivalent to 55500. I need to divide the sum by 55500/5=11100. we need to divide the values in to 5 groups, each group should have sum(count) evenly distributed, equivalent to 11110 (approximately)
I would start with 5 randomly chosen groups:
select t.*,
ntile(5) over (order by newid()) as grp
from t;
The sums should be pretty close. If you have a lot of records and the counts are reasonably distributed, then an nth sample usually does a pretty good job:
select t.*,
(row_number() over (order by count) % 5) as grp
from t;
If you have a situation where you have very disparate sizes for count and you need the optimal solution, then you have a hard problem.
You can try this script.
;WITH CTE AS (
SELECT * ,
RN = ROW_NUMBER() OVER (ORDER BY [count] DESC)
FROM T1
)
,CTE2 AS (
SELECT *,
RN2 = ROW_NUMBER() OVER(ORDER BY CEILING( RN / 5.00 ), (( 1 - CEILING( RN / 5.00 )) * [COUNT] ) DESC )
FROM CTE
)
SELECT
CTE2.rid,
CTE2.[count],
((RN2+1)%5) +1 GroupIndex,
SUM(CTE2.[count]) OVER (PARTITION BY ((RN2+1)%5)) CmlTotal
FROM CTE2
Result:
rid count GroupIndex CmlTotal
----------- ----------- -------------------- -----------
3 5678 1 10687
6 3990 1 10687
14 1019 1 10687
5 1099 2 10563
1 4567 2 10563
12 4897 2 10563
15 2387 3 11671
10 435 3 11671
13 8849 3 11671
9 7854 4 11890
7 780 4 11890
2 3256 4 11890
11 3455 5 11173
4 934 5 11173
8 6784 5 11173
Here's my go at it, what I've done is created a temp table with an identity column and an extra column ([Group]). The numbers are inserted in descending size order. Then, I've written a LOOP which inserts Groups 1 to 5 next to the largest 5 numbers in the [Group] column, then flips and inserts Groups 5 to 1 against the next 5 largest numbers, then it flips again and so on until it reaches the end of the table.
CREATE TABLE #T1
(
RID INT IDENTITY(1,1),
[Count] INT,
[Group] INT
)
INSERT INTO #T1 ([Count])
SELECT [Count] FROM T1 ORDER BY [Count] DESC
GO
DECLARE #ROWCOUNT INT = 1
WHILE #ROWCOUNT <= (SELECT MAX(RID) FROM #T1)
BEGIN
DECLARE #COUNT INT = (SELECT TOP 1 [COUNT]
FROM #T1 WHERE [GROUP] IS NULL ORDER BY [COUNT] DESC)
DECLARE #GROUP INT = 1
WHILE #GROUP <=5
BEGIN
UPDATE #T1 SET [GROUP] = #GROUP WHERE [COUNT] = #COUNT
SET #COUNT = (SELECT TOP 1 [COUNT] FROM #T1 WHERE [GROUP] IS NULL ORDER BY [COUNT] DESC)
SET #GROUP = #GROUP + 1
SET #ROWCOUNT = #ROWCOUNT +1
END
SET #GROUP = #GROUP - 1
WHILE #GROUP > 0
BEGIN
UPDATE #T1 SET [GROUP] = #GROUP WHERE [COUNT] = #COUNT
SET #COUNT = (SELECT TOP 1 [COUNT] FROM #T1 WHERE [GROUP] IS NULL ORDER BY [COUNT] DESC)
SET #GROUP = #GROUP - 1
SET #ROWCOUNT = #ROWCOUNT +1
END
END
The code below just demonstrates the actual numbers in each of the five groups and also shows the variance away from the sum of numbers divided by five.
DECLARE #AVGROUP INT = (SELECT SUM([COUNT])/5 FROM #T1);
WITH CTE (SUMCOUNT) AS
(
SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 1
UNION
SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 2
UNION
SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 3
UNION
SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 4
UNION
SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 5
)
,
CTE1 (SUMCOUNT,VARIANCE) AS
(
SELECT SUMCOUNT,#AVGROUP-SUMCOUNT FROM CTE
)
SELECT * FROM CTE1
Is this accurate enough? In other words, does a variance range of 1274 seem to be evenly distributed enough with these numbers? I think it might be possible to make it more accurate if required, if this is accurate enough, then fine.
Below is a code which shows how the Groups are comprised:
DECLARE #AVGROUP INT = (SELECT SUM([COUNT])/5 FROM #T1);
WITH CTE ([GROUP],N1,N2,N3,SUMCOUNT) AS
(
SELECT '1',
(SELECT [COUNT] FROM #T1 WHERE RID = 1),
(SELECT [COUNT] FROM #T1 WHERE RID = 10),
(SELECT [COUNT] FROM #T1 WHERE RID = 11),
(SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 1)
UNION
SELECT '2',
(SELECT [COUNT] FROM #T1 WHERE RID = 2),
(SELECT [COUNT] FROM #T1 WHERE RID = 9),
(SELECT [COUNT] FROM #T1 WHERE RID = 12),
(SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 2)
UNION
SELECT '3',
(SELECT [COUNT] FROM #T1 WHERE RID = 3),
(SELECT [COUNT] FROM #T1 WHERE RID = 8),
(SELECT [COUNT] FROM #T1 WHERE RID = 13),
(SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 3)
UNION
SELECT '4',
(SELECT [COUNT] FROM #T1 WHERE RID = 4),
(SELECT [COUNT] FROM #T1 WHERE RID = 7),
(SELECT [COUNT] FROM #T1 WHERE RID = 14),
(SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 4)
UNION
SELECT '5',
(SELECT [COUNT] FROM #T1 WHERE RID = 5),
(SELECT [COUNT] FROM #T1 WHERE RID = 6),
(SELECT [COUNT] FROM #T1 WHERE RID = 15),
(SELECT SUM([COUNT]) FROM #T1 WHERE [GROUP] = 5)
)
,
CTE1 ([GROUP],N1,N2,N3,SUMCOUNT,VARIANCE) AS
(
SELECT [GROUP],N1,N2,N3,SUMCOUNT,#AVGROUP-SUMCOUNT FROM CTE
)
SELECT * FROM CTE1

Update table in Sql

Table tblProductStock:
ID Name Qyt
1 X 50
2 Y 40
3 Z 30
Table tblStockMinus:
Id Name Qty
1 X 10
1 X 20
2 Y 30
3 Z 20
I want to update tblProductStock so that it will have:
ID Name Qyt
1 X 20
2 Y 10
3 Z 10
I have tried to use the following SQL request, but it didn't work correctly:
UPDATE ProductStock_Show
SET Quantity = ProductStock_Show.Quantity - ProductStock_Show_Minus.Quantity
FROM ProductStock_Show JOIN ProductStock_Show_Minus
ON ProductStock_Show_Minus.ProductId=ProductStock_Show.ProductId
This will give you required result.
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
You need to update this (but it depends in the RDBMS. This is for MS SQL Server)
Update t
set
t.qty=t3.qty from tblProductStock as t inner join
(
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
) as t3 on t.id=t3.id
DECLARE #Table1 TABLE
( ID int, Name varchar(1), Qyt int)
;
INSERT INTO #Table1
( ID , Name , Qyt )
VALUES
(1, 'X', 50),
(2, 'Y', 40),
(3, 'Z', 30)
;
DECLARE #Table2 TABLE
( Id int, Name varchar(1), Qty int)
;
INSERT INTO #Table2
( Id , Name , Qty )
VALUES
(1, 'X', 10),
(1, 'X', 20),
(2, 'Y', 30),
(3, 'Z', 20)
;
UPDATE #Table1 SET QYT =
t.Qyt - s from (
select
t.id,
t.Name,
t.Qyt ,
SUM(tt.Qty)S
FROM #Table1 t
INNER JOIN #Table2 tt
ON t.Name = tt.Name
GROUP BY t.id,t.Name,t.Qyt)T
SELECT * from #Table1

SQL: Deleting row which values already exist

I have a table that look like this:
ID | DATE | NAME | VALUE_1 | VALUE_2
1 | 27.11.2015 | Homer | A | B
2 | 27.11.2015 | Bart | C | B
3 | 28.11.2015 | Homer | A | C
4 | 28.11.2015 | Maggie | C | B
5 | 28.11.2015 | Bart | C | B
I currently delete duplicate rows (thank to this thread) using this code :
WITH cte AS
(SELECT ROW_NUMBER() OVER (PARTITION BY [VALUE_1], [VALUE_2]
ORDER BY [DATE] DESC) RN
FROM [MY_TABLE])
DELETE FROM cte
WHERE RN > 1
But this code don't delete exactly the lines I want. I would like to delete only rows which values already exist so in my example I would like to delete only line 5 because line 2 have the same values and is older.
Code to create my table and insert values:
CREATE TABLE [t_diff_values]
([id] INT IDENTITY NOT NULL PRIMARY KEY,
[date] DATETIME NOT NULL,
[name] VARCHAR(255) NOT NULL DEFAULT '',
[val1] CHAR(1) NOT NULL DEFAULT '',
[val2] CHAR(1) NOT NULL DEFAULT '');
INSERT INTO [t_diff_values] ([date], [name], [val1], [val2]) VALUES
('2015-11-27','Homer', 'A','B'),
('2015-11-27','Bart', 'C','B'),
('2015-11-28','Homer', 'A','C'),
('2015-11-28','Maggie', 'C','B'),
('2015-11-28','Bart', 'C','B');
You need to add one more CTE where you will index all islands and then apply your duplicate logic in second CTE:
DECLARE #t TABLE
(
ID INT ,
DATE DATE ,
VALUE_1 CHAR(1) ,
VALUE_2 CHAR(1)
)
INSERT INTO #t
VALUES ( 1, '20151127', 'A', 'B' ),
( 2, '20151128', 'C', 'B' ),
( 3, '20151129', 'A', 'B' ),
( 4, '20151130', 'A', 'B' );
WITH cte1
AS ( SELECT * ,
ROW_NUMBER() OVER ( ORDER BY date)
- ROW_NUMBER() OVER ( PARTITION BY VALUE_1, VALUE_2 ORDER BY DATE) AS gr
FROM #t
),
cte2
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY VALUE_1, VALUE_2, gr ORDER BY date) AS rn
FROM cte1
)
DELETE FROM cte2
WHERE rn > 1
SELECT *
FROM #t
Try this
CREATE TABLE [dbo].[Employee](
[ID] INT NOT NULL,
[Date] DateTime NOT NULL,
[VAL1] varchar(20) NOT NULL,
[VAL2] varchar(20) NOT NULL
)
INSERT INTO [dbo].[Employee] VALUES
(1,'2015-11-27 10:44:33.087','A','B')
INSERT INTO [dbo].[Employee] VALUES
(2,'2015-11-28 10:44:33.087','C','B')
INSERT INTO [dbo].[Employee] VALUES
(3,'2015-11-29 10:44:33.087','A','B')
INSERT INTO [dbo].[Employee] VALUES
(4,'2015-11-30 10:44:33.087','A','B')
with cte as(
select
*,
rn = row_number() over(partition by [VAL1], [VAL2]
ORDER BY [DATE] DESC),
cc = count(*) over(partition by [VAL1], [VAL2])
from [Employee]
)
delete
from cte
where
rn > 1 and rn < cc
select * from [Employee]
You could use this query:
WITH cte AS
(
SELECT RN = ROW_NUMBER() OVER (ORDER BY ID)
, *
FROM #data
)
DELETE FROM c1
--SELECT *
FROM CTE c1
INNER JOIN CTE c2 ON c1.RN +1 = c2.RN AND c1.VALUE_1 = c2.VALUE_1 AND c1.VALUE_2 = c2.VALUE_2
Here I order them by ID. If the next one (RN+1) has similar V1 and V2, it is deleted.
Output:
ID DATE VALUE_1 VALUE_2
1 2015-11-27 A B
2 2015-11-28 C B
4 2015-11-30 A B
Data:
declare #data table(ID int, [DATE] date, VALUE_1 char(1), VALUE_2 char(1));
insert into #data(ID, [DATE], VALUE_1, VALUE_2) values
(1, '20151127', 'A', 'B'),
(2, '20151128', 'C', 'B'),
(3, '20151129', 'A', 'B'),
(4, '20151130', 'A', 'B');