SQL adding numbers column - tsql

Let's say I have a table:
Table1
ID | Table2_ID | Title
1 1 Breaking_Bad
2 1 Breaking_Bad
3 2 Simpsons
4 1 House_Of_Cards
I want to rename the title by adding '_XX' (where XX is a number) to only to those entries that are the same title and have the same Table2_ID.
So end results would be
Table1
ID | Table2_ID | Title
1 1 Breaking_Bad_01
2 1 Breaking_Bad_02
3 2 Simpsons
4 1 House_Of_Cards
How could I do this with TSQL?

You can do this with
WITH T
AS (SELECT *,
COUNT(*) OVER (PARTITION BY Table2_ID, Title) AS Cnt,
ROW_NUMBER() OVER (PARTITION BY Table2_ID, Title ORDER BY ID) AS RN
FROM Table1)
UPDATE T
SET Title = Title + '_' + FORMAT(RN, 'D2')
WHERE Cnt > 1;
SQL Fiddle
Or if you are on a version without FORMAT
SET Title = Title + CASE WHEN RN < 10 THEN '_0' ELSE '_' END + CAST(RN AS VARCHAR(10))

Will this work in SQL Server? The padding to 2 digits would be straightforward.
UPDATE TABLE1 A SET TITLE = TITLE + '_' + (SELECT COUNT(*) FROM TABLE1 B WHERE A.TITLE=B.TITLE AND A.ID<=B.ID) WHERE A.ID IN (SELECT B.ID FROM TABLE1 B
WHERE A.Id<>B.ID and A.TITLE=B.TITLE)

Related

Capture First Character of Last Group of 1s in a Binary Series Part II: Multiple IDs

I have data something like this:
ID 1 1 1 1 1 1 1 1 1 1 1 1
Month J F M A M J J A S O N D
Status 1 0 0 1 0 1 0 0 1 1 1 1
ID 2 2 2 2 2 2 2 2 2 2 2 2
Month J F M A M J J A S O N D
Status 1 0 1 0 1 0 1 0 1 0 1 1
ID 3 3 3 3 3 3 3 3 3 3 3 3
Month J F M A M J J A S O N D
Status 0 0 0 0 0 0 0 0 0 0 0 1
Using t-SQL, I am trying to capture the month corresponding to the first STATUS = 1 in the last group of 1s for each ID, i.e., September, November and December in this example.
Here is the code I'm using:
IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL DROP TABLE #Temp1
;WITH PARTITIONED1 AS
(SELECT t0.ID
, t0.Year_Month
, LAST_VALUE(t0.Year_Month) OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS STATUS
, ROW_NUMBER() OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS rn1
FROM #Temp0 t0
)
SELECT *
INTO #Temp1
FROM PARTITIONED1 p1
ORDER BY t0.ID
, t0.Year_Month
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp
SELECT *
INTO #Temp
FROM #Temp1 t1
WHERE t1.rn1 = (SELECT MAX(b.rn1) + 1 FROM #Temp1 b WHERE b.STATUS = 0)
GROUP BY t1.ID
, t1.Year_Month
, t1.rn1
However, this just returns the last instance where STATUS = 1 is achieved overall as the first 1 of the last group of 1s, in this case January.
I've tried using CASE statements and grouping in various combinations (hence the intermediate step reading the data into #Temp1), but have not been able to get results for all three IDs; is anyone able to assist?
Thanks in advance!
Assuming Ju for June and Jl for July:
--Sample Data
IF OBJECT_ID('tempdb..#Temp0') IS NOT NULL DROP TABLE #Temp0
CREATE TABLE #Temp0 (ID INT, Year_Month VARCHAR(1), Status INT)
INSERT INTO #Temp0
VALUES(1,'J',1),(1,'F',0),(1,'M',0),(1,'A',1),(1,'M',0),(1,'J',1),(1,'J',0),(1,'A',0),(1,'S',1),(1,'O',1),(1,'N',1),(1,'D',1),(2,'J',1),(2,'F',0),(2,'M',1),(2,'A',0),(2,'M',1),(2,'J',0),(2,'J',1),(2,'A',0),(2,'S',1),(2,'O',0),(2,'N',1),(2,'D',1),(3,'J',0),(3,'F',0),(3,'M',0),(3,'A',0),(3,'M',0),(3,'J',0),(3,'J',0),(3,'A',0),(3,'S',0),(3,'O',0),(3,'N',0),(3,'D',1);
--Query
WITH A
AS ( SELECT *,
CASE Year_Month
WHEN 'J' THEN 1
WHEN 'F' THEN 2
WHEN 'M' THEN 3
WHEN 'A' THEN 4
WHEN 'M' THEN 5
WHEN 'Ju' THEN 6
WHEN 'Jl' THEN 7
WHEN 'A' THEN 8
WHEN 'S' THEN 9
WHEN 'O' THEN 10
WHEN 'N' THEN 11
WHEN 'D' THEN 12
END
AS MonthNumber
FROM #Temp0 ),
StartingPoints
AS ( SELECT ID,
Year_Month,
MonthNumber,
Status
FROM A
WHERE NOT EXISTS
(
SELECT 1
FROM A
AS B
WHERE B.ID=A.ID
AND B.Status=A.Status-1
) ),
MonthRanking
AS ( SELECT A.*,
ROW_NUMBER( ) OVER( PARTITION BY A.ID ORDER BY A.MonthNumber )
AS rownum
FROM A
INNER JOIN
(
SELECT ID,
MAX( MonthNumber )+1
AS StartOfLastGroup
FROM StartingPoints
GROUP BY ID
)
AS B
ON A.ID=B.ID
AND A.MonthNumber>=B.StartOfLastGroup )
SELECT *
FROM MonthRanking
WHERE rownum=1;
Results:
If Month Names are recorded in Full as in July, June then this would work as well:
WITH StartingPoints
AS (SELECT ID,
Year_Month,
MonthNUmber = MONTH('01-'+Year_Month+'-2010'),
Status
FROM #Temp0
WHERE NOT EXISTS
(
SELECT 1
FROM #Temp0 AS B
WHERE B.ID = #Temp0.ID
AND B.Status = #Temp0.Status - 1
)),
MonthRanking
AS (SELECT A.*,
ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY MONTH('01-'+A.Year_Month+'-2010')) AS rownum
FROM #Temp0 AS A
INNER JOIN
(
SELECT ID,
MAX(MonthNumber) + 1 AS StartOfLastGroup
FROM StartingPoints
GROUP BY ID
) AS B ON A.ID = B.ID
AND MONTH('01-'+A.Year_Month+'-2010') >= B.StartOfLastGroup)
SELECT *
FROM MonthRanking
WHERE rownum = 1;
Results:
And if we assume that the data is as Iamdave assumes then it simply like so:
WITH StartingPoints
AS (SELECT ID,
Year_Month,
Status
FROM #Temp0
WHERE NOT EXISTS
(
SELECT 1
FROM #Temp0 AS B
WHERE B.ID = #Temp0.ID
AND B.Status = #Temp0.Status - 1
)),
MonthRanking
AS (SELECT A.*,
ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY Year_Month) AS rownum
FROM #Temp0 AS A
INNER JOIN
(
SELECT ID,
MAX(Year_Month) + 1 AS StartOfLastGroup
FROM StartingPoints
GROUP BY ID
) AS B ON A.ID = B.ID
AND A.Year_Month >= B.StartOfLastGroup)
SELECT *
FROM MonthRanking
WHERE rownum = 1;
Results:
You can do this with a couple derived tables that stack two window functions on top of one another (which can't be done in the same select). I have assumed that your data is slightly different to the table you have provided, based on the column names in your query. If they are not as I have them below, I strongly recommend having a look at how you store your data:
declare #t table(ID int, YearMonth int,StatusValue bit);
insert into #t values (1,201501,1),(1,201502,0),(1,201503,0),(1,201504,1),(1,201505,0),(1,201506,1),(1,201507,0),(1,201508,0),(1,201509,1),(1,201510,1),(1,201511,1),(1,201512,1),(2,201601,1),(2,201602,0),(2,201603,1),(2,201604,0),(2,201605,1),(2,201606,0),(2,201607,1),(2,201608,0),(2,201609,1),(2,201610,0),(2,201611,1),(2,201612,1),(3,201701,0),(3,201702,0),(3,201703,0),(3,201704,0),(3,201705,0),(3,201706,0),(3,201707,0),(3,201708,0),(3,201709,0),(3,201710,0),(3,201711,0),(3,201712,1);
with c as
(
select ID
,YearMonth
,StatusValue
,case when StatusValue = 1
and lead(StatusValue,1,1) over (partition by ID
order by YearMonth desc) = 0
then 1
else 0
end as c
from #t
), sc as
(
select ID
,YearMonth
,StatusValue
,sum(c) over (partition by ID order by YearMonth desc) as sc
from c
where c = 1
)
select ID
,YearMonth
,StatusValue
from sc
where sc = 1
order by ID;
Output:
+----+-----------+-------------+
| ID | YearMonth | StatusValue |
+----+-----------+-------------+
| 1 | 201509 | 1 |
| 2 | 201611 | 1 |
| 3 | 201712 | 1 |
+----+-----------+-------------+

Row_number() over partition

I am working on peoplesoft. I have a requirement where I have to update the column value in a sequence ordered based on some ID.
For eg.
CA24100001648- 1
CA24100001648- 2
CA24100001664- 1
CA24100001664- 2
CA24100001664- 3
CA24100001664- 4
CA24100001664- 5
CA24100001664- 6
But, I am getting '1' as the value for all the rows on updating.
Here is my query, can anyone please help out on this.
UPDATE PS_UC_CA_CONT_STG C
SET C.CONTRACT_LINE_NUM2 = ( SELECT row_number() over(PARTITION BY D.CONTRACT_NUM
order by D.CONTRACT_NUM)
FROM PS_UC_CA_HDR_STG D
WHERE C.CONTRACT_NUM=D.CONTRACT_NUM );
Thanksenter image description here
update emp a
set comm =
(with cnt as ( select deptno,empno,row_number() over (partition by deptno order by deptno) rn from emp)
select c.rn from cnt c where c.empno=a.empno)

postgres - change one column to the same value by name

for example i have column that look like this:
name | id | value
A 1 aa
A 2 ab
B 3 bc
C 4 ca
C 5 cb
Is there any way to change it to this ?
name | id | value
A 1 aa
A 1 ab
B 3 bc
C 4 ca
C 4 cb
You can do this with a window function that numbers the rows, and use that select statement to supply the values for the update:
update the_table
set id = t.rn
from (
select name,
id,
dense_rank() over (order by name) as rn
from the_table
) t
where (t.name, t.id) = (the_table.name, the_table.id);
SQLFiddle example: http://sqlfiddle.com/#!15/0e987/1
This assumes that the existing combination (id, name) is unique. If that is not the case, you would need to use the ctid column to match the rows between the inner select and the table itself:
update the_table
set id = t.rn
from (
select name,
id,
ctid,
dense_rank() over (order by name) as rn
from the_table
) t
where t.ctid = the_table.ctid;

Remove duplicate with separate column check TSQL

I have 2 tables having same columns and permission records in it.
One columns named IsAllow is available in both tables.
I am getting records of both tables in combine using UNION
But want to skip similar records if IsAllow = 0 in any one column - I don't want those records. But UNION returns all records and am getting confused.
Below are columns
IsAllow, UserId, FunctionActionId
I tried union but it gives both records. I want to exclude IsAllow = 0 in either table.
Sample data table 1
IsAllow UserId FunctionActionId
1 2 5
1 2 8
Sample data table 2
IsAllow UserId FunctionActionId
0 2 5 (should be excluded)
1 2 15
You can try this:
;with cte as(select *, row_number()
over(partition by UserId, FunctionActionId order by IsAllow desc) rn
from
(select * from table1
union all
select * from table2) t)
select * from cte where rn = 1 and IsAllow = 1
Version2:
select distinct coalesce(t1.UserId, t2.UserId) as UserId,
coalesce(t1.FunctionActionId, t2.FunctionActionId) as FunctionActionId,
1 as IsAllow
from tabl1 t1
full join table2 t2 on t1.UserId = t2.UserId and
t1.FunctionActionId = t2.FunctionActionId
where (t1.IsAllow = 1 and t2.IsAllow = 1) or
(t1.IsAllow = 1 and t2.IsAllow is null) or
(t1.IsAllow is null and t2.IsAllow = 1)

sql join if value exists in other table then Count it

I have following tables.
Table A
UserID | key 1 | A 2 | B 3 | A 4 | C 5 |
Table B
UserID | Num1 | 501 | 3002 |3 | 1004 | 20
I have query like this
SELECT COUNT(key) AS cnt, key
FROM A
WHERE key <> ''
GROUP BY key
ORDER BY cnt DESC
The results should be something like this
key | cnt A | 2 B | 1 C | 1
What I would like to add is Joining Table B.
If UserID has value in Num in Table B, I would like to count UserID with/Num Grouped by key
Here is desired results
key | cnt | Has Num? A | 2 | 2 B | 1 | 0 C | 1 | 1
I tried to write subquery but I can't attach it to main query. Subquery is something like this.
SELECT COUNT(DISTINCT UserID) AS num
FROM B
LEFT OUTER JOIN A ON B.UserID = A.UserID
WHERE Num <>'' AND key <> ''
GROUP BY key
If I'm understanding this correctly, what you're looking for is a count of the Keys in Table A when they were used by a UserID, and then a count of the number of unique UserIDs in Table B who both appeared in the first Table A query and had a Num.
Try this:
SELECT a.[Key], COUNT(a.[Key]) AS cnt, isNull(SUM(b.bCnt), 0) AS [Has Num?]
FROM #TableA a
LEFT OUTER JOIN (
SELECT b.UserID, 1
FROM #TableB b
WHERE LEN(b.Num) > 0
GROUP BY b.UserID
) b (UserID, bCnt) ON b.UserID = a.UserID
WHERE LEN(a.[Key]) > 0
GROUP BY a.[Key]
This query gives the results that you were expecting.
DECLARE #TableA TABLE(UserID INT, [Key] CHAR(1))
INSERT INTO #TableA VALUES(1,'A'),(2,'B'),(3,'A'),(4,'C'),(5,'')
DECLARE #TableB TABLE(UserID INT, Num INT NULL)
INSERT INTO #TableB VALUES(1,50),(1,300),(2,NULL),(3,100),(4,20)
SELECT x.[Key],x.Cnt,y.[Has Num?]
FROM
( SELECT [Key],Cnt = COUNT([Key])
FROM #TableA
WHERE LEN([Key])>0
GROUP BY [Key]
)X
JOIN
(
SELECT a.[Key],[Has Num?] = COUNT(b.Num)
FROM #TableA a
JOIN #TableB b ON a.UserID = b.UserID
GROUP BY a.[Key]
)Y
ON x.[Key] = Y.[Key]
Key Cnt Has Num?
A 2 3
B 1 0
C 1 1
How about an OUTER APPLY
SELECT [Key], COUNT(a.[Key]) AS cnt, SUM(x.NumCount) AS [Has Num?]
FROM #TableA a
OUTER APPLY (SELECT COUNT(NUM) AS NumCount
FROM #TableB b
WHERE b.UserId = a.UserId AND Num IS NOT NULL
) x
WHERE [Key] <> ''
GROUP BY [Key]
ORDER BY cnt DESC
Result:
Key cnt Has Num?
---- ----------- -----------
A 2 3
B 1 0
C 1 1