Change the Value on Duplicate Rows - sql-server

I need assistance on how to code duplicate Line IDs for the same Purchase Order and assign the additional line IDs with a new number. I would like to use Line ID + 100 for the additional duplicate rows. For example if Purchase Order #11 has three Line ID #5s then the first would stay as 5 and the second would be 501 and the third would be 502, however, I can only get a 1, 2 or 3 or if no duplicate just 1. I am not sure what to use to increment. I am hoping some one can assist or guide. Thank you
PurchaseOrderID LineID PackingList NewLineID
11 1 12323 1
11 1 78786 2
11 2 67523 1
11 3 44559 1
11 4 44559 1
11 5 96545 1
11 5 12323 2
11 5 34569 3
The Packing Slip causes the duplicates for the same line ID.
Below is what I am trying to use which is giving me the above NewLineID:
SELECT
PurchaseOrderID,
LineID,
PackingList,
ROW_NUMBER() over
(
partition by PurchaseOrderID, LineID
order by PurchaseOrderID, LineID
) as NewLineID
FROM PurchaseOrderTransactions

Using ROW_NUMBER and CASE:
WITH Cte AS(
SELECT
PurchaseOrderID,
LineID,
PackingList,
RN = ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID)
FROM PurchaseOrderTransactions
)
SELECT
PurchaseOrderID,
LineID,
PackingList,
NewLineID = CASE
WHEN RN = 1 THEN LineID
ELSE (LineID * 100) + (RN - 1)
END
FROM Cte
Without using a CTE:
SELECT
PurchaseOrderID,
LineID,
PackingList,
NewLineID =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID) = 1 THEN LineID
ELSE (LineID * 100) + (ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID) - 1)
END
FROM PurchaseOrderTransactions
SQL Fiddle
| PurchaseOrderID | LineID | PackingList | NewLineID |
|-----------------|--------|-------------|-----------|
| 11 | 1 | 12323 | 1 |
| 11 | 1 | 78786 | 101 |
| 11 | 2 | 67523 | 2 |
| 11 | 3 | 44559 | 3 |
| 11 | 4 | 44559 | 4 |
| 11 | 5 | 96545 | 5 |
| 11 | 5 | 12323 | 501 |
| 11 | 5 | 34569 | 502 |

Related

MSSQL select where following (sequence) rows with the same column value as current column equale to X

how do i do a select where count = select all sequence rows has the same column value as current column value only if there 3 in sequence (row after row with no holes)
NAME | NUM | DATE
---------------------------------
Name 1 | 1 | '2019-01-07 12:11:11:001'
Name 2 | 1 | '2019-01-07 12:11:12:002'
Name 3 | 3 | '2019-01-07 12:11:13:003'
Name 4 | 2 | '2019-01-07 12:11:14:004'
Name 5 | 2 | '2019-01-07 12:11:15:005'
Name 6 | 2 | '2019-01-07 12:11:16:006'
Name 7 | 4 | '2019-01-07 12:11:17:007'
Name 8 | 5 | '2019-01-07 12:11:18:008'
The results should be where count sequence=3
NAME | NUM | DATE
---------------------------------
Name 4 | 2 | '2019-01-07 12:11:14:004'
Name 5 | 2 | '2019-01-07 12:11:15:005'
Name 6 | 2 | '2019-01-07 12:11:16:006'
because 2 appears 3 times in sequence
You can use the following query:
SELECT [NAME], [NUM], [DATE],
ROW_NUMBER() OVER (ORDER BY [DATE]) -
ROW_NUMBER() OVER (PARTITION BY NUM ORDER BY [DATE]) AS grp
FROM mytable
to get:
NAME NUM DATE grp
----------------------------------------
Name 1 1 2019-01-07 12:11:11 0
Name 2 1 2019-01-07 12:11:12 0
Name 4 2 2019-01-07 12:11:13 3
Name 5 2 2019-01-07 12:11:14 3
Name 6 2 2019-01-07 12:11:15 3
Name 3 3 2019-01-07 12:11:16 2
Name 7 4 2019-01-07 12:11:17 6
Name 8 5 2019-01-07 12:11:18 7
As you can see calculated column grp can be used in order to identify islands of consecutive records having the same NUM value.
You can then wrap the above query in a CTE and do:
;WITH GroupCTE AS (
SELECT [NAME], [NUM], [DATE],
ROW_NUMBER() OVER (ORDER BY [DATE]) -
ROW_NUMBER() OVER (PARTITION BY NUM ORDER BY [DATE]) AS grp
FROM mytable
)
SELECT t.*
FROM GroupCTE AS t
JOIN (SELECT NUM, grp
FROM GroupCTE
GROUP BY NUM, grp
HAVING COUNT(*) = 3) AS g ON t.NUM = g.NUM AND t.grp = g.grp

How to combine multiple rows into one row and multiple column in SQL Server?

I have different tables through I made temp table and here is the result set of temp table:
car_id | car_type | status | count
--------+----------+---------+------
100421 | 1 | 1 | 9
100421 | 1 | 2 | 8
100421 | 1 | 3 | 3
100421 | 2 | 1 | 6
100421 | 2 | 2 | 8
100421 | 2 | 3 | 3
100422 | 1 | 1 | 5
100422 | 1 | 2 | 8
100422 | 1 | 3 | 7
Here is the meaning of status column:
1 as sale
2 as purchase
3 as return
Now I want to show this result set as below
car_id | car_type | sale | purchase | return
--------+----------+------+----------+----------
100421 | 1 | 9 | 8 | 3
100421 | 2 | 6 | 8 | 3
100422 | 1 | 5 | 8 | 7
I tried but unable to generate this result set. Can anyone help?
You can also use a CASE expression.
Query
select [car_id], [car_type],
max(case [status] when 1 then [count] end) as [sale],
max(case [status] when 2 then [count] end) as [purchase],
max(case [status] when 3 then [count] end) as [return]
from [your_table_name]
group by [car_id], [car_type]
order by [car_id];
Try this
select car_id ,car_type, [1] as Sale,[2] as Purchase,[3] as [return]
from (select car_id , car_type , [status] ,[count] from tempTable)d
pivot(sum([count]) for [status] in([1],[2],[3]) ) as pvt
also you can remove the subquery if you don't have any condition
like
select car_id ,car_type, [1] as Sale,[2] as Purchase,[3] as [return]
from tempTable d
pivot(sum([count]) for [status] in([1],[2],[3]) ) as pvt

Limit the rows if same id repeats

I have a table like below
ID | s_id | mark
-----------------------
1 | 2 | 10
2 | 5 | 9
3 | 7 | 8
4 | 2 | 8
5 | 2 | 10
6 | 5 | 7
7 | 3 | 7
8 | 2 | 9
9 | 5 | 8
I need to get SQL query for output like:-
mark column need to be in descending order.
Same s_id should not repeat more than 2 times
if same s_id repeats more than 2 times, ignore the 3rd result
ID | s_id | mark
-----------------------
1 | 2 | 10
2 | 2 | 9
3 | 3 | 7
4 | 5 | 9
5 | 5 | 8
6 | 7 | 8
Assuming you're using SQL Server, you can just use ROW_NUMBER() to assign a row number to each s_id group based on a descending order of the mark column. Then, retain only those records where this row number is 1 or 2.
SELECT
t.ID, t.s_id, t.mark
FROM
(
SELECT ID, s_id, mark, ROW_NUMBER() OVER (PARTITION BY s_id ORDER BY mark DESC) rn
FROM yourTable
) t
WHERE t.rn <= 2
ORDER BY t.s_id;
Note: You'll notice that the record (s_id, mark) = (2, 10) appears twice in my result set. Based on your input data, this is what is generated. If you really intended to also remove duplicate (s_id, mark) pairs, then let us know and a small correction can be added to the query.
Output:
Demo here:
Rextester
try this code.
;WITH cte
AS (
SELECT ROW_NUMBER() OVER (PARTITION BY s_id
ORDER BY ( SELECT 0)) RN,ID,s_id,mark
FROM aaa)
select RN,ID,s_id,mark FROM cte
WHERE RN <= 2
order by s_id,mark desc;

LAG of MIN in SQL Analytic

I have a table containing employees id, year id, client id, and the number of sales. For example:
--------------------------------------
id_emp | id_year | sales | client id
--------------------------------------
4 | 1 | 14 | 1
4 | 1 | 10 | 2
4 | 2 | 11 | 1
4 | 2 | 17 | 2
For a employee, I want to obtain rows with the minimum sales per year and the minimum sales of the previous year.
One of the queries I tried is the following:
select distinct
id_emp,
id_year,
MIN(sales) OVER(partition by id_emp, id_year) AS min_sales,
LAG(min(sales), 1) OVER(PARTITION BY id_emp, id_year
ORDER BY id_emp, id_year) AS previous
from facts
where id_emp = 4
group by id_emp, id_year, sales;
I get the result:
-------------------------------------
id_emp | id_year | sales | previous
-------------------------------------
4 | 1 | 10 | (null)
4 | 1 | 10 | 10
4 | 2 | 11 | (null)
but I expect to get:
-------------------------------------
id_emp | id_year | sales | previous
-------------------------------------
4 | 1 | 10 | (null)
4 | 2 | 11 | 10
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE EMPLOYEE_SALES ( id_emp, id_year, sales, client_id ) AS
SELECT 4, 1, 14, 1 FROM DUAL
UNION ALL SELECT 4, 1, 10, 2 FROM DUAL
UNION ALL SELECT 4, 2, 11, 1 FROM DUAL
UNION ALL SELECT 4, 2, 17, 2 FROM DUAL;
Query 1:
SELECT ID_EMP,
ID_YEAR,
SALES AS SALES,
LAG( SALES ) OVER ( PARTITION BY ID_EMP ORDER BY ID_YEAR ) AS PREVIOUS
FROM (
SELECT e.*,
ROW_NUMBER() OVER ( PARTITION BY id_emp, id_year ORDER BY sales ) AS RN
FROM EMPLOYEE_SALES e
)
WHERE rn = 1
Query 2:
SELECT ID_EMP,
ID_YEAR,
MIN( SALES ) AS SALES,
LAG( MIN( SALES ) ) OVER ( PARTITION BY ID_EMP ORDER BY ID_YEAR ) AS PREVIOUS
FROM EMPLOYEE_SALES
GROUP BY ID_EMP, ID_YEAR
Results - Both give the same output:
| ID_EMP | ID_YEAR | SALES | PREVIOUS |
|--------|---------|-------|----------|
| 4 | 1 | 10 | (null) |
| 4 | 2 | 11 | 10 |
You mean like this?
select id_emp, id_year, min(sales) as min_sales,
lag(min(sales)) over (partition by id_emp order by id_year) as prev_year_min_sales
from facts
where id_emp = 4
group by id_emp, id_year;
I believe it is because you are using sales column in your group by statement.
Try to remove it and just use
GROUP BY id_emp,id_year
You could get your desired output using ROW_NUMBER() and LAG() analytic functions.
For example,
Table
SQL> SELECT * FROM t;
ID_EMP ID_YEAR SALES CLIENT_ID
---------- ---------- ---------- ----------
4 1 14 1
4 1 10 2
4 2 11 1
4 2 17 2
Query
SQL> WITH DATA AS
2 (SELECT t.*,
3 row_number() OVER(PARTITION BY id_emp, id_year ORDER BY sales) rn
4 FROM t
5 )
6 SELECT id_emp,
7 id_year ,
8 sales ,
9 lag(sales) over(order by sales) previous
10 FROM DATA
11 WHERE rn =1;
ID_EMP ID_YEAR SALES PREVIOUS
---------- ---------- ---------- ----------
4 1 10
4 2 11 10

Running "Group By" Ordinal Counter Based on a "Flip" Column

Usually I'm decent at set-based tsql problems. But this one is beating me.
I've been working 3 days on converting a while-loop procedure into a setbased one. I've gotten to the point below.......but can't make the final jump.
I have the following rows. MyOrdinal will be "in order" ... and a second column (MyMarker) will alternate between having a value and being null. Whenever this "flip" occurs on MyMarker, I would like to increment a "group by" ordinal counter by one. Whenever the "flip" values are non-null or null, these are grouped together as a set.
I've tried several things, but it was too ugly to post. That and since moving to ORM, I don't spend as much time in the tsql anymore.
declare #Holder table ( MyOrdinal int not null , MyMarker int , MyGroupNumber int )
INSERT INTO #Holder (MyOrdinal, MyMarker)
Select 1 , 1
union all Select 2, 2
union all Select 3, null
union all Select 4, 3
union all Select 5, 4
union all Select 6, 5
union all Select 7, 6
union all Select 8, 7
union all Select 9, 8
union all Select 10, 9
union all Select 11, 10
union all Select 12, 11
union all Select 13, 12
union all Select 14, 13
union all Select 15, 14
union all Select 16, 15
union all Select 17, null
union all Select 18, null
union all Select 19, null
union all Select 20, 16
union all Select 21, 17
union all Select 22, 18
union all Select 23, null
union all Select 24, null
union all Select 25, 19
union all Select 26, 20
union all Select 27, null
union all Select 28, 21
Select * from #Holder
Desired Output
| MyOrdinal | MyMarker | MyGroupNumber |
|-----------|----------|---------------|
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | null | 2 |
| 4 | 3 | 3 |
| 5 | 4 | 3 |
| 6 | 5 | 3 |
| 7 | 6 | 3 |
| 8 | 7 | 3 |
| 9 | 8 | 3 |
| 10 | 9 | 3 |
| 11 | 10 | 3 |
| 12 | 11 | 3 |
| 13 | 12 | 3 |
| 14 | 13 | 3 |
| 15 | 14 | 3 |
| 16 | 15 | 3 |
| 17 | null | 4 |
| 18 | null | 4 |
| 19 | null | 4 |
| 20 | 16 | 5 |
| 21 | 17 | 5 |
| 22 | 18 | 5 |
| 23 | null | 6 |
| 24 | null | 6 |
| 25 | 19 | 7 |
| 26 | 20 | 7 |
| 27 | null | 8 |
| 28 | 21 | 9 |
Try this one:
First, this assigns a same ROW_NUMBER for continuous Non-NULL MyMarker. ROW_NUMBER is NULL for NULL MyMarkers. After that, you want to add a ROW_NUMBER for NULL MyMarkers such that the value is between the previous NON-NULL and the next NON-NULL. Then use DENSE_RANK to finally assign MyGroupNumber:
SQL Fiddle
;WITH Cte AS(
SELECT *,
RN = ROW_NUMBER() OVER(ORDER BY MyOrdinal) - MyMarker + 1
FROM #Holder
),
CteApply AS(
SELECT
t.MyOrdinal,
t.MyMarker,
MyGroupNumber =
CASE
WHEN RN IS NULL THEN x.NewRN
ELSE RN
END
FROM Cte t
OUTER APPLY(
SELECT TOP 1 RN * 1.1 AS NewRN
FROM Cte
WHERE
t.MyOrdinal > MyOrdinal
AND MyMarker IS NOT NULL
ORDER BY MyOrdinal DESC
)x
)
SELECT
MyOrdinal,
MyMarker,
MyGroupNumber = DENSE_RANK() OVER(ORDER BY MyGroupNumber)
FROM CteApply
For Sql Server 2012:
select *, sum(b) over(order by myordinal)
from(select *,
case when (lag(mymarker) over(order by myordinal) is not null
and mymarker is null) or
(lag(mymarker) over(order by myordinal) is null
and mymarker is not null)
then 1 else 0 end as b
from #Holder) t
First you mark rows with 1 where there is a change from null to not null or from not null to null. Other columns are marked as 0. Then running sum of all rows till current.
Fiddle http://sqlfiddle.com/#!6/9eecb/5015
For Sql Server 2008:
with cte1 as (select *,
case when (select max(enddate) from t ti
where ti.ruleid = t.ruleid and ti.startdate < t.startdate) = startdate
then 0 else 1 end as b
from t),
cte2 as(select *, sum(b) over(partition by ruleid order by startdate) as s
from cte1)
select RuleID,
Name,
min(startdate),
case when count(*) = count(enddate)
then max(enddate) else null end from cte2
group by s, ruleid, name
Fiddle http://sqlfiddle.com/#!6/4191d/6

Resources