Using code sample below, how can I add missing Param for every EntityId without using WHILE? In the end, I want for every EntityId a row for Param 1, Param 2 and Param 3. I'm using SQL Server 2012.
DECLARE #Data TABLE
(
ID INT IDENTITY(1,1),
EntityId INT,
[Param] VARCHAR(25),
[Value] VARCHAR(25)
)
DECLARE #Param TABLE
(
[Param] VARCHAR(25)
)
INSERT INTO #Param([Param]) VALUES ('Param 1')
INSERT INTO #Param([Param]) VALUES ('Param 2')
INSERT INTO #Param([Param]) VALUES ('Param 3')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(1, 'Param 1', 'Value 1')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(1, 'Param 2', 'Value 2')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(1, 'Param 3', 'Value 3')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(2, 'Param 1', 'Value 1')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(2, 'Param 3', 'Value 3')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(3, 'Param 1', 'Value 1')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(3, 'Param 3', 'Value 3')
INSERT INTO #Data (EntityId, [Param], [Value]) VALUES(4, 'Param 1', 'Value 1')
With a CROSS JOIN of #Param and the distinct EntityIds of #Data and a LEFT JOIN to #Data:
INSERT INTO #Data (EntityId, [Param])
SELECT e.EntityId, p.[Param]
FROM #Param p
CROSS JOIN (SELECT DISTINCT EntityId FROM #Data) AS e
LEFT JOIN #Data d ON d.EntityId = e.EntityId AND d.[Param] = p.[Param]
WHERE d.EntityId IS NULL
See the demo.
I'm not sure if you want the column [Value] to be populated with values just like [Param].
Note my comments.
-- 1. SAMPLE DATA
DECLARE #Data TABLE
(
ID INT IDENTITY(1,1),
EntityId INT,
[Param] VARCHAR(25),
[Value] VARCHAR(25)
);
DECLARE #Param TABLE
(
[Param] VARCHAR(25)
);
INSERT INTO #Param([Param])
VALUES ('Param 1'),('Param 2'),('Param 3')
INSERT INTO #Data (EntityId, [Param], [Value])
VALUES(1, 'Param 1', 'Value 1'),(1, 'Param 2', 'Value 2'),(1, 'Param 3', 'Value 3'),
(2, 'Param 1', 'Value 1'),(2, 'Param 3', 'Value 3'),(3, 'Param 1', 'Value 1'),
(3, 'Param 3', 'Value 3'),(4, 'Param 1', 'Value 1');
-- 2. How to get ALL values
SELECT
dist.EntityId,
p.[Param],
[Value] = REPLACE(p.[Param], 'Param','Value')
FROM
(
SELECT DISTINCT d.EntityId
FROM #data AS d -- OR WHEREEVER I CAN GET A DISTINCT LIST OF EntityIDs
) AS dist(EntityId)
CROSS JOIN #param AS p;
-- 3. How to identify MISSING values
SELECT
dist.EntityId,
[Param] = CAST(p.[Param] AS varchar(25)),
[Value] = CAST(REPLACE(p.[Param], 'Param','Value') AS varchar(25))
FROM
(
SELECT DISTINCT d.EntityId
FROM #data AS d -- OR WHEREEVER I CAN GET A DISTINCT LIST OF EntityIDs
) AS dist(EntityId)
CROSS JOIN #param AS p
EXCEPT
SELECT d.EntityId, d.[param], d.[value]
FROM #data AS d;
-- 4. How to add missing values
INSERT #data
SELECT
dist.EntityId,
[Param] = CAST(p.[Param] AS varchar(25)),
[Value] = CAST(REPLACE(p.[Param], 'Param','Value') AS varchar(25))
FROM
(
SELECT DISTINCT d.EntityId
FROM #data AS d -- OR WHEREEVER I CAN GET A DISTINCT LIST OF EntityIDs
) AS dist(EntityId)
CROSS JOIN #param AS p
EXCEPT
SELECT d.EntityId, d.[param], d.[value]
FROM #data AS d;
If you want to choose the EntityId which records will be inserted so this could be it.
declare #eId int
set #eId = 4
insert into #Data (EntityId, [Param], [Value])
select #eId, [Param], 'Value ' + CAST(RIGHT([Param],1) AS varchar(1))
from #Param
where [Param] NOT IN (select [Param] from #Data where EntityId = #eId)
Related
I am trying to unpivot the table in sql but it's throwing an error. Help is appreciated
create table #test (id int ,GroupType varchar(50),State_NM varchar(20))
Insert Into #test values (100, 'Facility' ,'TX')
Insert Into #test values (100, 'Group' ,NULL)
Insert Into #test values (100, 'JobTitle' ,'TX')
Insert Into #test values (100, 'JobTitle' ,'NC')
Insert Into #test values (101, 'Facility' ,'NM')
Insert Into #test values (101, 'Group' ,'TX')
Insert Into #test values (102, 'Facility' ,'TX')
Insert Into #test values (102, 'Group' ,Null)
Insert Into #test values (102, 'Jobtitle' ,'CA')
select * from #test
SELECT ID, facility,Group,JobTitle FROM
(SELECT ID,GroupType,State_NM FROM #test )Tab1
PIVOT
(
State_NM FOR GroupType IN ([facility],[Group[,[JobTitle])) AS Tab2
ORDER BY Tab2.Name
Expected Result
with string_agg() to "feed" your pivot
Example or dbFiddle
Select *
From (
select id
,GroupType
,Value = string_agg(state_NM,',')
from #test
Group by id,groupType
) src
Pivot ( max(value) for GroupType IN ([facility],[Group],[JobTitle])) pvt
Results
id facility Group JobTitle
100 TX NULL TX,NC
101 NM TX NULL
102 TX NULL CA
UPDATE: <=2016 Version
Select *
From (
select id
,GroupType
,Value = stuff( (Select ',' +state_NM From #test Where ID=A.ID and GroupType=A.GroupType For XML Path ('')),1,1,'')
From #test A
Group By id,GroupType
) src
Pivot ( max(value) for GroupType IN ([facility],[Group],[JobTitle])) pvt
Sample data:
declare #docs table (docid int, name varchar(10), isfolder int)
declare #hierarchy table (childid int, parent varchar(10))
insert #docs values (1, 'Doc1', 0)
insert #docs values (2, 'Doc2', 0 )
insert #docs values (3, 'Folder1', 1 )
insert #docs values (4, 'Folder2', 1 )
insert #docs values (5, 'SubFolderA', 1 )
insert #docs values (6, 'SubFolderB', 1 )
insert #hierarchy values (1, 5)
insert #hierarchy values (1, 6)
insert #hierarchy values (2, 6)
insert #hierarchy values (5, 3)
insert #hierarchy values (6, 4)
I want to list the data above so I end up with the documents (isfolder = 0) and the folder paths that they are in.
Expected output:
DocId Name Path
--------------------------------------
1 Doc1 Folder1\SubFolderA
1 Doc1 Folder2\SubFolderB
2 Doc2 Folder2\SubFolderB
CTE
I started to write this next CTE as it said this can be used to create my output but I am wrong somewhere
;WITH folderCTE (docid, name) AS
(
-- Anchor member
SELECT docid, CAST(name AS varchar(max)) AS name
FROM #docs
WHERE isfolder = 0
UNION ALL
-- Recursive member that references expression_name.
SELECT d.docid, CAST(folderCTE.Name + '\' + d.name AS varchar(max)) AS name
FROM folderCTE
INNER JOIN #docs d ON d.docid = folderCTE.docid
)
-- references expression name
SELECT *
FROM folderCTE
Can anyone show me how I should be doing a CTE for this?
If you use a CTE which just expands the hierarchy for folders, and a second one to build the hierarchy, you can simply join to this to get the folder for your docs:
declare #docs table (docid int, name varchar(10), isfolder int)
declare #hierarchy table (childid int, parentid varchar(10))
insert #docs values (1, 'Doc1', 0)
insert #docs values (2, 'Doc2', 0 )
insert #docs values (3, 'Folder1', 1 )
insert #docs values (4, 'Folder2', 1 )
insert #docs values (5, 'SubFolderA', 1 )
insert #docs values (6, 'SubFolderB', 1 )
insert #docs values (7, 'SuperFold1', 1 )
insert #hierarchy values (1, 5)
insert #hierarchy values (1, 6)
insert #hierarchy values (2, 6)
insert #hierarchy values (5, 3)
insert #hierarchy values (6, 4)
insert #hierarchy values (3, 7)
;WITH folderCTE
AS
(
select docid, cast(name as nvarchar(max)) as name, parentid
from #docs d
left join #hierarchy h on d.docid=h.childid
where d.isfolder = 1
),
folderHierarchyCTE
as
(
select docid, cast(name as nvarchar(max)) as name
from folderCTE where parentid is null
union all
select d.docid, cast(p.name + '/' + d.name as nvarchar(max))
from folderCTE d
inner join folderHierarchyCTE p on d.parentid = p.docid
)
SELECT d.docid, d.name, f.name
FROM #docs d
inner join #hierarchy h on h.childid=d.docid
inner join folderHierarchyCTE f on h.parentid=f.docid
where d.isfolder = 0
My table structure:
declare #TestTable as table
(
id int,
somedate date,
somevalue int
)
insert into #TestTable values
(1, '2019-01-01', 1000),
(2, '2019-01-02', null ),
(3, '2019-01-03', null),
(4, '2019-01-04', null ),
(5, '2019-01-05', 800),
(6, '2019-01-06', null),
(7, '2019-01-07', null),
(8, '2019-01-08', null),
(9, '2019-01-09', null),
(10, '2019-01-10', 700)
Repeat the column value until any change in value of column (somevalue).. Is it possible with window functions?
Required output:
You can achieve that by using window function as well.
try the following:
select id, somevalue, newvalue=max(somevalue) over (partition by c)
from
(
select id, somevalue
,c=count(somevalue) over (order by id)
from #testtable
) t
order by id;
Please find the demo here.
Try this below logic-
DEMO HERE
SELECT A.*,
(
SELECT somevalue
FROM #TestTable
WHERE id = (
SELECT MAX(id)
FROM #TestTable
WHERE id <= A.id
AND somevalue IS NOT NULL
)
) new_column
FROM #TestTable A
ORDER BY A.id
You can achieve this using COALESCE (Transact-SQL)
.
SELECT
[id]
, somedate
, COALESCE(somevalue,
(SELECT TOP (1) somevalue
FROM #TestTable AS p2
WHERE
p2.somevalue IS NOT NULL
AND p2.[id] <= p.[id] ORDER BY p2.[id] DESC))
FROM #TestTable AS p;
Here is the live db<>fiddle demo.
How can I select only information that start with a #?
I have a table with 5 columns and in one of the columns i.e. the comments column there is information like:
#2345 Changed by Mark
Paul changed ticket number #5923
Someone changed ticket number #5823 and #9333
#3555 is missing from the list, can only see #5789, #9000 and #4568
In the sample of 4 rows above, I want my select statement to return only ticket numbers as shown below:
comments
#2345
#5923
#5823, #9333
#5789, #9000, #4568
Someone said regular expressions can do the work for me but I am fresh graduate and have never seen such before. Can you help me please??
Select the required fields from your database table using SQL, then perform regex operations on the result in another language such as c++, php etc. when outputting your result to the client
First Create Function To extract #numeric values
CREATE FUNCTION dbo.udf_GetNumeric
(
#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256
)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^#0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^#0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
GO
By Using Below Code we can Extract the numeric values
Declare #TempTable TABLE(ID Int Identity,Value varchar(1000))
INSERT INTO #TempTable
SELECT '#2345 Changed by Mark'
UNION ALL SELECT 'Paul changed ticket number #5923'
UNION ALL SELECT 'Someone changed ticket number #5823 and #9333'
UNION ALL SELECT '#3555 is missing from the list, can only see #5789, #9000 and #4568'
SELECT ID,
RIGHT(LTRIM(REPLACE(Value,'#',' ,#')),LEN(RTRIM(LTRIM(REPLACE(Value,'#',' ,#'))))-1)AS Value FROM
(
SELECT ID,dbo.udf_GetNumeric(Value) AS Value From #TempTable
)Dt
If you need to extract Numeric values Instead of pre-fixed wirh '#' Symbol
SELECT ID,
REPLACE(RIGHT(LTRIM(REPLACE(Value,'#',' ,#')),LEN(RTRIM(LTRIM(REPLACE(Value,'#',' ,#'))))-1),'#',' ')AS Value FROM
(
SELECT ID,dbo.udf_GetNumeric(Value) AS Value From #TempTable
)Dt
OutPut
ID Value
----------
1 #2345
2 #5923
3 #5823 ,#9333
4 #3555 ,#5789 ,#9000 ,#4568
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
Drop table #TempTable
CREATE TABLE [dbo].#TempTable(
[ID] [int] NOT NULL,
[Value] [varchar](1000) NULL
) ON [PRIMARY]
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (1, N'#2345 Changed by Mark #111111,767677,33333,#5656 vbvb')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (2, N'Paul changed ticket number #5923,5555555 464646 #010101,5555544rrr,wwww AND #4 ')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (3, N'Someone changed ticket number #5823 and #9333,7777')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (4, N'#3555 is missing from the list, can only see #5789, #9000 and #4568')
GO
;WITH cte
AS
(
SELECT ID,Split.a.value('.', 'VARCHAR(1000)') AS TablesData
FROM (
SELECT ID,CAST('<S>' + REPLACE(Value, ' ', '</S><S>') + '</S>' AS XML) AS TablesData
FROM #TempTable
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)
,Final
AS
(
SELECT ID,TablesData FROM
(
SELECT ID, Split.a.value('.', 'VARCHAR(1000)') AS TablesData,CHARINDEX('#',Split.a.value('.', 'VARCHAR(1000)')) AS Data2
FROM (
SELECT ID,CAST('<S>' + REPLACE(TablesData, ',', '</S><S>') + '</S>' AS XML) AS TablesData
FROM cte
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)DT
WHERE dt.Data2 <>0
)
SELECT DISTINCT ID
,STUFF((
SELECT ', ' + CAST(TablesData AS VARCHAR(50))
FROM Final i
WHERE i.ID = o.ID
FOR XML PATH('')
), 1, 1, '') AS ColumnsWith#ValuesOnly
FROM Final o
ORDER BY 1 ASC
OutPut
ID ColumnsWith#ValuesOnly
---------------------------
1 #2345, #111111, #5656
2 #5923, #010101, #4
3 #5823, #9333
4 #3555, #5789, #9000, #4568
The best way is to use this script below:
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
Drop table #TempTable
CREATE TABLE [dbo].#TempTable(
[ID] [int] NOT NULL,
[Value] [varchar](1000) NULL
) ON [PRIMARY]
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (1, N'#2345 Changed by Mark #111111,767677,33333,#5656 vbvb')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (2, N'Paul changed ticket number #5923,5555555 464646 #010101,5555544rrr,wwww AND #4 ')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (3, N'Someone changed ticket number #5823 and #9333,7777')
GO
INSERT [dbo].#TempTable ([ID], [Value]) VALUES (4, N'#3555 is missing from the list, can only see #5789, #9000 and #4568')
GO
;WITH cte
AS
(
SELECT ID,Split.a.value('.', 'VARCHAR(1000)') AS TablesData
FROM (
SELECT ID,CAST('<S>' + REPLACE(Value, ' ', '</S><S>') + '</S>' AS XML) AS TablesData
FROM #TempTable
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)
,Final
AS
(
SELECT ID,TablesData FROM
(
SELECT ID, Split.a.value('.', 'VARCHAR(1000)') AS TablesData,CHARINDEX('#',Split.a.value('.', 'VARCHAR(1000)')) AS Data2
FROM (
SELECT ID,CAST('<S>' + REPLACE(TablesData, ',', '</S><S>') + '</S>' AS XML) AS TablesData
FROM cte
) AS A
CROSS APPLY TablesData.nodes('/S') AS Split(a)
)DT
WHERE dt.Data2 <>0
)
SELECT DISTINCT ID
,STUFF((
SELECT ', ' + CAST(TablesData AS VARCHAR(50))
FROM Final i
WHERE i.ID = o.ID
FOR XML PATH('')
), 1, 1, '') AS ColumnsWith#ValuesOnly
FROM Final o
ORDER BY 1 ASC
I got situation to find duplicates from different sourceport system.
for Ex: I got table like below:
declare #table table (id int,portnumber int, [sourceport] varchar(50), sourcereportedDate datetime )
insert into #table values (1, 1111, 'north' , '2016-08-20 09:44:30.847')
insert into #table values (2, 1111, 'north' , '2016-08-21 09:44:30.847')
insert into #table values (3, 1111, 'north' , '2016-08-22 09:44:30.847')
insert into #table values (4, 2222, 'north' , '2016-08-20 09:44:30.847')
insert into #table values (5, 2222, 'north' , '2016-08-26 09:44:30.847')
insert into #table values (6, 2222, 'south' , '2016-08-22 09:44:30.847')
insert into #table values (7, 3333, 'south' , '2016-08-10 09:44:30.847')
insert into #table values (8, 3333, 'north' , '2016-08-12 09:44:30.847')
insert into #table values (9, 4444, 'north' , '2016-08-20 09:44:30.847')
insert into #table values (10, 5555, 'south' , '2016-08-21 09:44:30.847')
insert into #table values (11, 5555, 'south' , '2016-08-27 09:44:30.847')
insert into #table values (12, 6666, 'south' , '2016-08-10 09:44:30.847')
insert into #table values (13, 6666, 'north' , '2016-08-21 09:44:30.847')
insert into #table values (14, 6666, 'south' , '2016-08-09 09:44:30.847')
Now I want to find duplicates with 'portnumber' should be same and 'sourceport' should be different. if 'portnumber' same and 'sourceport' same it should not be duplicate.
and also I need additional column which holds the Id of greatest 'sourcereportedDate' date
I want get output like below:
(4, 2222, 'north' , '2016-08-20 09:44:30.847',5)
(5, 2222, 'north' , '2016-08-26 09:44:30.847','latest')
(6, 2222, 'south' , '2016-08-22 09:44:30.847',5)
(7, 3333, 'south' , '2016-08-10 09:44:30.847',8)
(8, 3333, 'north' , '2016-08-12 09:44:30.847','latest')
(12, 6666, 'south' , '2016-08-10 09:44:30.847',13)
(13, 6666, 'north' , '2016-08-21 09:44:30.847','latest')
(14, 6666, 'south' , '2016-08-09 09:44:30.847',13)
Thanks in advance.
Please try this (i still think it can be further optimized)-
;with DupWithMaxDate as (
select
a.portnumber,
sourcereportedDate = max(a.sourcereportedDate)
from #table a
left join #table b on b.portnumber = a.portnumber and b.sourceport <> a.sourceport
where b.portnumber is not null
group by a.portnumber
),
DupWithMaxID as (
select
a.portnumber,
max_id = a.id
from DupWithMaxDate x
inner join #table a on a.portnumber = x.portnumber and a.sourcereportedDate = x.sourcereportedDate
)
select
a.id,
a.portnumber,
a.sourceport,
a.sourcereportedDate,
new_column = case when a.id = x.max_id then 'Latest' else convert(varchar(10), x.max_id) end
from DupWithMaxID x
inner join #table a on a.portnumber = x.portnumber
Updated above query -
;with DuplicateWithMaxID as (
select
portnumber = a.portnumber,
max_id = a.id,
rank_id = row_number() over (partition by a.portnumber order by a.sourcereportedDate desc)
from #table a
inner join #table b on b.portnumber = a.portnumber and b.sourceport <> a.sourceport
)
select
a.id,
a.portnumber,
a.sourceport,
a.sourcereportedDate,
new_column = case when a.id = x.max_id then 'Latest' else convert(varchar(10), x.max_id) end
from
DuplicateWithMaxID x
inner join #table a on a.portnumber = x.portnumber
where
x.rank_id = 1
Try this:
;
with
dis as
(
select distinct portnumber, sourceport
from #table
),
dup as
(
select portnumber
from dis
group by portnumber
having count(1) > 1
),
mx as
(
select
dup.portnumber,
max(t.sourcereportedDate) as sourcereportedDate
from
dup
join
#table as t
on
t.portnumber = dup.portnumber
group by
dup.portnumber
),
mxi as
(
select
mx.portnumber,
t.id
from
mx
left join
#table as t
on
t.portnumber = mx.portnumber
and t.sourcereportedDate = mx.sourcereportedDate
)
select
t.id,
t.portnumber,
t.sourceport,
t.sourcereportedDate,
case when t.id = mxi.id
then 'latest'
else cast(mxi.id as varchar(10))
end as latest
from
dup
join
#table as t
on
t.portnumber = dup.portnumber
join
mxi
on
mxi.portnumber = t.portnumber
left join
mx
on
mx.portnumber = t.portnumber
and mx.sourcereportedDate = t.sourcereportedDate