Updating first record of a group of records t-sql - sql-server

I have a table like this
CREATE TABLE [dbo].[tblUserLink](
[IDUserLink] [int] IDENTITY(1,1) NOT NULL,
[IDUser] [int] NOT NULL,
[IDRegie] [varchar](50) NOT NULL,
[DefaultAgency] [bit] NULL
)
I'm looking for a query /script to update the field DefaultAgency. I'd like to set it to 1 for the first record that comes for each group of record with a same IDUser.
example :
IDUserLink IDUser IDRegie DefaultAgency (Goal)
1 1 1 null DefaultAgency to be set to 1
2 1 2 null
3 1 3 null
4 2 2 null DefaultAgency to be set to 1
5 2 1 null
6 3 1 null DefaultAgency to be set to 1
...etc
Can I achieve this using a simple sql query or should I script it ?

update tblUserLink
set DefaultAgency = 1
where IDUserLink in
(select min(IDUserLink) from tblUserLink group by IDUser)

If you're on SQL Server 2005+, you can use a common table expression:
with cte as (
select *,
row_number() over (partition by IDUser order by IDUserLink) as [rn]
from tblUserLink
)
update c
set DefaultAgency = 1
from cte as c
where c.rn = 1

Related

T-SQL Get Values from Lookup table and use in view / stored procedure

I couldn't find that via search, so I guess I am not asking it the right way, so help is welcome.
We have a lookup table:
Id Name
------------------
1 "Test"
2 "New"
3 "InProgress"
Table2:
StatusId SomethingElse
1
2
Table 1
ID Other Other StatusId (Fkey to Table2) ...
Then we have a view that selects from several tables and one of the columns is a CASE Statement:
SELECT * FROM Table1 t1 -- has million records
CASE When t1.StatusId = 1 THEN (SELECT Name from LOOKUP table where ID = 1) END --'Test'
CASE When t1.StatusId = 2 THEN (SELECT Name from LOOKUP table where ID = 2) END --'New'
CASE When t3.Date is not null THEN (SELECT Name from LOOKUP table where ID = 3) END --'In Progress'
-- AND ALSO the case look at other tables another 5-6 tables and there are conditions from there
INNER JOIN Table2 t2 on ...
INNER JOIN Table3 t3 on ...
As you see these are really static values.
I want to load them once into variables, e.g.
#LookUp1 = SELECT [NAME] FROM LookUP WHERE Id = 1,
#LookUp2 = SELECT [NAME] FROM LookUP WHERE Id = 2
and replace the select in the CASE statement to this:
When StatusId = 1 THEN #LookUp
When StatusId = 2 THEN #LookUp2
The view loops through millions of records and it gets really slow to do the select from Lookup table for every row.
Why not simply use a join?
SELECT <columns list from main table>, Lt.Name
FROM <main table> As Mt -- Do not use such aliases in real code!
JOIN <SecondaryTable> As St -- this represents your Table3
ON <condition>
[LEFT] JOIN <Lookup table> As Lt
ON Mt.StatusId = Lt.Id
OR (Lt.Id = 3 AND St.Date is not null)
Of course, replace <columns list from main table> with the actual columns list, <main table> with the name of the main table and so on.
The join might be an inner or left join, depending on the nullability of the StatusId column in the main table and if it's nullable, on what you want to get in such cases (either a row with null name or no row at all).
I've put together a little demonstration to show you exactly what I mean.
Create and populate sample tables (Please save us this step in your future questions):
CREATE TABLE LookUp (Id int, Name varchar(10));
INSERT INTO LookUp (Id, Name) VALUES
(1, 'Test'), (2, 'New'), (3, 'InProgress');
CREATE TABLE Table1 (Id int not null, StatusId int null);
INSERT INTO Table1(Id, StatusId)
SELECT n, CASE WHEN n % 3 = 0 THEN NULL ELSE (n % 3) END
FROM
(
SELECT TOP 30 ROW_NUMBER() OVER(ORDER BY ##SPID) As n
FROM sys.objects
) tally
CREATE TABLE Table3
(
Id int not null,
Date date null
)
INSERT INTO Table3 (Id, Date)
SELECT Id, CASE WHEN StatusId IS NULL AND Id % 4 = 0 THEN GetDate() END
FROM Table1
The query:
SELECT Table1.Id,
Table1.StatusId,
Table3.Date,
LookUp.Name
FROM Table1
JOIN Table3
ON Table1.Id = Table3.Id
LEFT JOIN LookUp
ON Table1.StatusId = LookUp.Id
OR (LookUp.Id = 3 AND Table3.Date IS NOT NULL)
Results:
Id StatusId Date Name
1 1 NULL Test
2 2 NULL New
3 NULL NULL NULL
4 1 NULL Test
5 2 NULL New
6 NULL NULL NULL
7 1 NULL Test
8 2 NULL New
9 NULL NULL NULL
10 1 NULL Test
11 2 NULL New
12 NULL 27.06.2019 InProgress
13 1 NULL Test
14 2 NULL New
15 NULL NULL NULL
16 1 NULL Test
17 2 NULL New
18 NULL NULL NULL
19 1 NULL Test
20 2 NULL New
21 NULL NULL NULL
22 1 NULL Test
23 2 NULL New
24 NULL 27.06.2019 InProgress
25 1 NULL Test
26 2 NULL New
27 NULL NULL NULL
28 1 NULL Test
29 2 NULL New
30 NULL NULL NULL
You can also see a live demo on rextester.
Create a SQL function which return Name according to Id.
Create FUNCTION [dbo].[GetLookUpValue]
(
#Id int
)
RETURNS varchar(500)
AS BEGIN
return(Select Name from LOOKUP_table with(nolock) where Id=#Id)
END

How to retrieve row when null then take above record in table,with out using loop and update

id name
--------------
1 ACTIVE
2 NULL
3 NULL
4 NULL
5 COMPLETED
6 NULL
7 COMPLETED
8 COMPLETED
9 ACTIVE
10 NULL
11 ACTIVE
Output:
id name
--------------
1 ACTIVE
2 ACTIVE
3 ACTIVE
4 ACTIVE
5 COMPLETED
6 COMPLETED
7 COMPLETED
8 COMPLETED
9 ACTIVE
10 ACTIVE
11 ACTIVE
Task: retrieve null records with above values without using a loop and update.
in will come select statement.
With DDL and Sample data:
CREATE TABLE #Sample (ID int, [Name] varchar(9));
INSERT INTO #Sample
VALUES (1,'ACTIVE'),
(2,NULL),
(3,NULL),
(4,NULL),
(5,'COMPLETED'),
(6,NULL),
(7,'COMPLETED'),
(8,'COMPLETED'),
(9,'ACTIVE'),
(10,NULL),
(11,'ACTIVE');
GO
SELECT *
FROM #Sample;
UPDATE S
SET [Name] = (SELECT TOP 1 [Name]
FROM #Sample sq
WHERE sq.ID < S.ID
AND sq.[Name] IS NOT NULL
ORDER BY sq.ID DESC)
FROM #Sample S
WHERE S.[Name] IS NULL;
SELECT *
FROM #Sample;
GO
DROP TABLE #Sample;
Assuming window functions are supported in your version of SQL Server, this can be done with classifying consecutive nulls in the name column to the same group as the first occurring name for an id. Then use max to get the name for the group and use it to update.
with cte as (
select id,name,max(name) over(partition by grp) as new_name
from (select *, sum(case when name is null then 0 else 1 end) over(order by id) as grp
from tbl
) t
)
update cte set name = new_name
where name is null;

Finding an Hierarchy of row in SQL Server

I am unable to find the logic for below question in SQL Server.
I have a table like below.
id ParentID
---------------
1 NULL
2 NULL
3 1
4 2
5 3
6 5
I need a query which will return hierarchy of a row, like this:
Hierarchy id ParentID
----------------------------
1 1 NULL
1 2 NULL
2 3 1
2 4 2
3 5 3
4 6 5
I will explain the hierarchy:
For any row if ParentId is null then Hierarchy will be 1
Any row if ParentId is not null and ParentId's ParentId is null then 2
Any row if ParentId is not null, ParentId's ParentId is not null and next ParentId's ParentId is null then 3
And it goes on
How can write the query for this logic.
You can achieve this with a recursive query:
(in the below example your initial table data is stored in #a):
;With DATA AS (
SELECT 1 as hierarchy
,Id
,parentid
from #a
where parentid is null
UNION ALL
SELECT Data.Hierarchy + 1
,a.id
,a.parentid
FROM #a a
INNER JOIN DATA
ON Data.id = a.parentid
)
SELECT *
FROM DATA
ORDER BY hierarchy, Id

parent id hierarchy identification MS SqlServer2012

I have this code
create table #temp
(
order_id int not null identity(1,1) primary key
,sid int
,created_date date
,parent_order_id int
)
insert into #temp
(
sid
,created_date
)values(1,'2017-01-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-02-01',1),(1,'2017-03-01',2),(1,'2017-04-01',3)
insert into #temp
(
sid
,created_date
)values(1,'2017-06-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-07-01',5),(1,'2017-08-01',6)
select * from #temp
Whenever parent_order_id is null which indicates it is a new order. After that customer can add items associated to that order. so we have parent_order_id filled for these associations. But I want to know what is the first order_id for each association child order.I am looking for an output like below.
`order_id sid created_date parent_order_id original_order_id
1 1 2017-01-01 NULL 1
2 1 2017-02-01 1 1
3 1 2017-03-01 2 1
4 1 2017-04-01 3 1
5 1 2017-06-01 NULL 4
6 1 2017-07-01 5 4
7 1 2017-08-01 6 4
`
any help is appreciated. Thanks in advance.
With the following piece of code you can get results you are expecting.
;WITH cte (order_id, original_order_id)
AS
(
SELECT order_id, order_id AS original_order_id
FROM #temp WHERE parent_order_id IS NULL
UNION ALL
SELECT o.order_id AS order_id, cte.original_order_id AS original_order_id
FROM #temp AS o
JOIN cte
ON o.parent_order_id = cte.order_id
)
SELECT #temp.order_id, #temp.sid, #temp.created_date, #temp.parent_order_id, cte.original_order_id
FROM #temp
JOIN cte ON cte.order_id=#temp.order_id
ORDER BY cte.order_id
Please be aware, that there are certain limits on recursion as this for CTE. Currently it is 100 which can be pushed up to 32767.

SQL Query - Almost pivot table-like?

Another stupid question here regarding a SQL scenario.
Given data such as:
FieldKey DocumentKey FieldId FieldValue
1 00001c55-aab3-4df8-a07e-8eac162fa075 TITLE Mass Import 18355
2 00001c55-aab3-4df8-a07e-8eac162fa075 1 00001c55-aab3-4df8-a07e-8eac162fa075
3 00001c55-aab3-4df8-a07e-8eac162fa075 2 9F-2F-CF-76-27-E7-5B-C9-27-CE-23-45-68-3F-E2-89
4 00001c55-aab3-4df8-a07e-8eac162fa075 3 18355
5 00001c55-aab3-4df8-a07e-8eac162fa075 4 94-3C-84-B1-6A-AA-FD-25-F1-C0-D2-43-CD-D3-57-D6
6 00001c55-aab3-4df8-a07e-8eac162fa075 5 Created by C# mass import
7 00002205-00D3-4495-B65A-A7B1FD2AE7F2 TITLE Mass Import 1494780
8 00002205-00D3-4495-B65A-A7B1FD2AE7F2 1 00002205-00D3-4495-B65A-A7B1FD2AE7F2
9 00002205-00D3-4495-B65A-A7B1FD2AE7F2 2 870386312
10 00002205-00D3-4495-B65A-A7B1FD2AE7F2 3 1494780
11 00002205-00D3-4495-B65A-A7B1FD2AE7F2 4 -1929051324
13 00002342-6de0-4110-b576-fd32f96b2858 TITLE Mass Import 387008
14 00002342-6de0-4110-b576-fd32f96b2858 1 00002342-6de0-4110-b576-fd32f96b2858
15 00002342-6de0-4110-b576-fd32f96b2858 2 B0-CB-DF-ED-48-DC-C4-E8-B0-6F-1B-1D-81-2D-6D-51
16 00002342-6de0-4110-b576-fd32f96b2858 3 387008
With table structure:
[FieldKey] [bigint] IDENTITY(1,1) NOT NULL,
[DocumentKey] [char](36) NOT NULL,
[FieldId] [varchar](10) NOT NULL,
[FieldValue] [varchar](255) NOT NULL
What is the best way to flip this data horizontally? Ideally:
DocumentKey TITLE 1 2 3 4 5
00001c55-aab3-4df8-a07e-8eac162fa075 mytitle val1 val2 val3 val4 val5
00002205-00D3-4495-B65A-A7B1FD2AE7F2 mytitle2 val6 val7 val8 val9
00002342-6de0-4110-b576-fd32f96b2858 mytitle3 vl10 vl11 vl12
I thought a pivot table might work and it is close, but the problem is I don't need an aggregation which is required for a SQL pivot. I just want to flip the data. The number of columns (1-5 plus TITLE in my example) could be anywhere between TITLE plus 1-30.
Maybe I'm just being dense, but any ideas would be appreciated.
I think that you are on the right track with a PIVOT. You are going to have a aggregate on the value column. But as you say you will have 1-30 column plus the title column. That requires a dynamic pivot
Here is a suggestion (that is only for SQL Server 2005+):
Test data
CREATE TABLE Table1
(
[FieldKey] [bigint] NOT NULL,
[DocumentKey] [char](36) NOT NULL,
[FieldId] [varchar](10) NOT NULL,
[FieldValue] [varchar](255) NOT NULL
)
INSERT INTO Table1
VALUES
(1,'00001c55-aab3-4df8-a07e-8eac162fa075','TITLE','Mass Import 18355'),
(2,'00001c55-aab3-4df8-a07e-8eac162fa075','1','00001c55-aab3-4df8-a07e-8eac162fa075'),
(3,'00001c55-aab3-4df8-a07e-8eac162fa075','2','9F-2F-CF-76-27-E7-5B-C9-27-CE-23-45-68-3F-E2-89'),
(4,'00001c55-aab3-4df8-a07e-8eac162fa075','3','18355'),
(5,'00001c55-aab3-4df8-a07e-8eac162fa075','4','94-3C-84-B1-6A-AA-FD-25-F1-C0-D2-43-CD-D3-57-D6'),
(6,'00001c55-aab3-4df8-a07e-8eac162fa075','5','Created by C# mass import'),
(7,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','TITLE','Mass Import 1494780'),
(8,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','1','00002205-00D3-4495-B65A-A7B1FD2AE7F2'),
(9,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','2','870386312'),
(10,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','3','1494780'),
(11,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','4','-1929051324'),
(13,'00002342-6de0-4110-b576-fd32f96b2858','TITLE','Mass Import 387008'),
(14,'00002342-6de0-4110-b576-fd32f96b2858','1','00002342-6de0-4110-b576-fd32f96b2858'),
(15,'00002342-6de0-4110-b576-fd32f96b2858','2','B0-CB-DF-ED-48-DC-C4-E8-B0-6F-1B-1D-81-2D-6D-51'),
(16,'00002342-6de0-4110-b576-fd32f96b2858','3','387008')
Find the unique columns
DECLARE #cols VARCHAR(MAX)
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY Table1.FieldId
ORDER BY Table1.FieldId) AS RowNbr,
Table1.*
FROM
Table1
)
SELECT #cols=STUFF
(
(
SELECT
',' +QUOTENAME(CTE.FieldId)
FROM
CTE
WHERE
CTE.RowNbr=1
ORDER BY
LEN(CTE.FieldId) DESC,
CTE.FieldId
FOR XML PATH('')
)
,1,1,'')
We need to order so that TITLE comes first. The FOR XML PATH is to concat the columns.
Dynamic pivot
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
Table1.DocumentKey,
Table1.FieldId,
Table1.FieldValue
FROM
Table1
) AS p
PIVOT
(
MAX(FieldValue)
FOR FieldId IN('+#cols+')
) AS p'
EXECUTE(#query)
Clean up after myself (not required)
DROP TABLE Table1
If you're using SQL Server 2005+, you can use PIVOT operator.
select [DocumentKey], [TITLE], [1], [2], [3], [4], [5]
from (select [DocumentKey], FieldId, FieldValue from TableName) t
pivot (max(FieldValue) for FieldID in ([TITLE], [1], [2], [3], [4], [5])) as pvt
order by [DocumentKey]
You would have to add the additional columns, 6 - 30.

Resources