Combine multiple SQL fields into 1 output row - sql

Having a SQL table like
UserID |Attribute | Value
1 |Username | Marius
1 |Password | Fubar
I want to create an output like:
1 | Marius | Fubar
Maybe I'm just too tired to see it, doesn't sound too complicated, but I just can't seem to figure it out. Any help is appreciated.

Why don't you use self joins, ie. :
select u1.userid, u1.value, u2.value
from yourtable u1
inner join yourtable u2 on u2.userid=u1.userid
where u1.attribute='Username' and u2.attribute='Password';

Would something like...
SELECT userID,
GROUP_CONCAT (Value SEPARATOR '|')
FROM my_table
GROUP BY UserID;
be what you are looking for?

If you keep your data that way, you will need to do a crosstab query and pivot your rows into columns. If you are using Microsoft SQL Server, check out "crosstab query" and the pivot operator in Books Online.

Edited:
One column per result:
If you try to combine multiple Attributes with the same UserID it would be something like this:
Short query (one UserID):
declare #concattedtext varchar(1000)
SELECT #concattedtext=coalesce(#concattedtext + '|', '') + Value
FROM #users WHERE UserID=1
SELECT #concattedtext
RESULT with your example data:
1 | Marius | Fubar
Full query (all UserID's)
-- Your source table
CREATE Table #users (UserID int, Attribute varchar(50), Value varchar(50))
-- some entries
INSERT into #users (UserID, Attribute, Value)
VALUES (1, 'Test1', 'attr1')
INSERT into #users (UserID, Attribute, Value)
VALUES (1, 'Test2', 'attr2')
INSERT into #users (UserID, Attribute, Value)
VALUES (1, 'Test3', 'attr3')
INSERT into #users (UserID, Attribute, Value)
VALUES (2, 'Test4', 'attr4')
-- ids table variable (for distinct UserID's)
DECLARE #ids TABLE
(
rownum int IDENTITY (1, 1) Primary key NOT NULL,
UserID int
)
-- Output table variable
DECLARE #out TABLE
(
rownum int IDENTITY (1, 1) Primary key NOT NULL,
UserID int,
ConcatText varchar(1000)
)
-- get distinct id's
INSERT INTO #ids(UserID)
SELECT DISTINCT(UserID) FROM #users
-- Foreach vars
declare #RowCnt int
declare #MaxRows int
select #RowCnt = 1
select #MaxRows=count(*) from #ids
-- UserID
declare #id int
declare #concattedtext varchar(1000)
-- process each id
while #RowCnt <= #MaxRows
begin
SET #id = 0
SELECT #id=UserID
FROM #ids WHERE rownum=#RowCnt
SET #concattedtext = CONVERT(nvarchar(50), #id)
FROM #ids WHERE rownum=#RowCnt
SELECT #concattedtext=coalesce(#concattedtext + '|', '') + Value
FROM #users WHERE UserID=#id
INSERT INTO #out(UserID, ConcatText)
VALUES (#id, #concattedtext)
-- next UserID
Select #RowCnt = #RowCnt + 1
end
SELECT * FROM #out
DROP TABLE #users
Result:
rownum|UserID|ConcatTex
1 | 1 |1|attr1|attr2|attr3
2 | 2 |2|attr4
DROP TABLE #users
You might need a sort field to get your parameters in your requested order.
Multiple columns
Your data needs to have an equal count of attributes if you like to get a table with multiple columns. And you still need to take care about the ordering.
In this case a hardcoded query with a group by would be your choice.

Related

Logic Needed for after Parsing Json

DECLARE #json NVARCHAR(MAX)
DECLARE #userid int
SET #userid=3
SET #json =
N'[{"ID":1,"Roles":[1,2]},{"ID":2, "Roles":[1,2,3]},{"ID":3,"Roles":[1,2,3,4]}]'
BEGIN
SELECT ID, R.[Value] AS [Role]
FROM OPENJSON(#json) WITH (
ID INT,
[Roles] NVARCHAR(MAX) AS JSON
)
CROSS APPLY OPENJSON([Roles]) R
end
Above query giving below result.
ID ROLE
1 1
1 2
2 1
2 2
2 3
3 1
3 2
3 3
3 4
CREATE TABLE A(ID INT,ROLE INT)
i want logic to compare above QUERY output with another table(table A) whether above ID is present or not if ID Is present in that table then Role is present or not for corresponding ID,if Role is not present i want to insert Role for the ID.
I believe you can use EXCEPT to filter rows that are not already present in the table:
DECLARE #a TABLE (ID INT, ROLE INT);
INSERT INTO #a VALUES
(1, 2),
(2, 2),
(3, 3);
INSERT INTO #a
SELECT ID, R.[Value] AS [Role]
FROM OPENJSON(#json) WITH (
ID INT,
[Roles] NVARCHAR(MAX) AS JSON
)
CROSS APPLY OPENJSON([Roles]) R
EXCEPT
SELECT ID, ROLE
FROM #a;
Test

SQL Server : split column into table in a trigger

I have a table that looks something like this:
UserID Email
-----------------------------------
1 1_0#email.com;1_1#email.com
2 2_0#email.com;2_1#email.com
3 3_0#email.com;3_3#email.com
And I need to create a temp table that will look like this:
UserID Email
-----------------------------------
1 1_0#email.com
1 1_1#email.com
2 2_0#email.com
2 2_1#email.com
3 3_0#email.com
3 3_1#email.com
The temp table will be used in a update trigger and I was wondering if there is a more elegant approach than doing something like this:
-- Create temp table to hold the result table
CREATE TABLE #resultTable(
UserID int,
Email nvarchar(50)
)
-- Create temp table to help iterate through table
CREATE TABLE #tempTable(
ID int IDENTITY(1,1),
UserID int,
Email nvarchar(50)
)
-- Insert data from updated table into temp table
INSERT INTO #tempTable
SELECT [UserId], [Email]
FROM inserted
-- Iterate through temp table
DECLARE #count int = ##ROWCOUNT
DECLARE #index int = 1
WHILE (#index <= #count)
BEGIN
DECLARE #userID int
DECLARE #email nvarchar(50)
-- Get the user ID and email values
SELECT
#userID = [UserID], #email = [Email]
FROM #tempTable
WHERE [ID] = #index
-- Insert the parsed email address into the result table
INSERT INTO #resultTable([UserID], [Email])
SELECT #userID, [Data]
FROM myFunctionThatSplitsAColumnIntoATable(#email, ';')
SET #index = #index + 1
END
-- Do stuff with the result table
You'd better avoid iterative approaches when using T-SQL unless strictly necessary, specially inside triggers.
You can use the APPLY operator.
From MSDN:
The APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query.
So, you can try to replace all your code with this:
INSERT INTO #resultTable(UserID, Email)
SELECT T1.UserID
,T2.Data
FROM updated T1
CROSS APPLY myFunctionThatSplitsAColumnIntoATable(T1.Email, ';') AS T2

Assign multiple values to Table variable in SQL

DECLARE #ID INT
SET #ID = (select top 1 USER_REQ_JOB_ID
from T8504_USER_REQ_JOB
where JOB_GRP_ID = 160
order by LST_UPDT_TS desc)
SELECT INPUT_PARM_VAL_TX
from TBL_RPT_JOB_INPUT_PARAM
where USER_REQ_JOB_ID = #ID
This returns these results:
USA
USCC
6
7
2
These five records what I get I want to assign to five different variables to use in stored procedure.
I was trying with table variable like this :
declare #CID table (
Region Char(3)
,Segment Char(3)
,MasterContractId int
,ctcid int
,templateid int)
insert into #CID (Region,Segment,MasterContractId,ctcid,templateid)
But how to insert that 5 rows here?
INSERT INTO #CID
select * from
(
select
'Temp' + convert(char(1), row_number() over (order by (select 0))) as columnName,
INPUT_PARM_VAL_TX as Value
from TBL_RPT_JOB_INPUT_PARAM where USER_REQ_JOB_ID = #ID
) d
pivot
(
max(value)
for columnname in (Temp1, Temp2, Temp3, Temp4, Temp5)
) piv;
See if this helps.
Take a look at this fiddle for an example.
Courtesy:
Add row number to this T-SQL query
Efficiently convert rows to columns in sql server
EDIT: The sql adds an extra column to generate row numbers to use it as an extra column, which is pivoted as column heading.
it's really gross, but one way you could probably do it is this (though you'll need to apply it to your case):
http://sqlfiddle.com/#!6/d41d8/21507
declare #table TABLE (value varchar(50))
INSERT INTO #table
VALUES ('first')
INSERT INTO #table
VALUES ('second')
INSERT INTO #table
VALUES (3)
INSERT INTO #table
VALUES (4)
DECLARE #temp TABLE (id int identity(1,1), value varchar(50))
INSERT INTO #temp
SELECT [value]
FROM #table t
SELECT *
FROM #temp
DECLARE #CID TABLE (Region varchar(50), cont varchar(50), another int, andAnother int)
INSERT INTO #CID
(
Region,
cont,
another,
andAnother
)
VALUES
(
(SELECT value FROM #temp WHERE id = 1), -- Region - varchar
(SELECT value FROM #temp WHERE id = 2), -- cont - varchar
(SELECT value FROM #temp WHERE id = 3), -- another - int
(SELECT value FROM #temp WHERE id = 4) -- andAnother - int
)
SELECT * FROM #cid
note that i assumed you're using mssql, you did not specify

How to write a stored procedure which contains multiple parameters for in query?

I want to write a stored procedure like this
Create Proc dbo.GetApplicantsByIDs
as
Select * from Applicants where ID in (1,2,3,4)
How i can pass 1,2,3 as parameters and these ids may be multiple.
You can send your id's as XML to the SP.
create procedure dbo.GetApplicantsByIDs
#IDList xml
as
-- Table to hold the id's
declare #IDs table(ID int primary key)
-- Fill table with id's
insert into #IDs(ID)
select X.ID.value('.', 'int')
from #IDList.nodes('/i') as X(ID)
select *
from Applicants
where ID in (select ID
from #IDs)
The parameter string should look like this:
'<i>1</i><i>2</i><i>3</i>'
I think there is a better solution.
You can create a function like:
CREATE FUNCTION [dbo].[Split] (#sep char(1), #s varchar(8000))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, [stop]) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, [stop] + 1, CHARINDEX(#sep, #s, [stop] + 1)
FROM Pieces
WHERE [stop] > 0
)
SELECT pn as [index],
SUBSTRING(#s, start, CASE WHEN [stop] > 0 THEN [stop]-start ELSE 8000 END) AS value
FROM Pieces
)
Then you can get the result from for input data '20,10,15,18,19'
SELECT * FROM [dbo].[Split](',', '20,10,15,18,19')
The result will be:
index value
1 20
2 10
3 15
4 18
5 19
And I can rewrite your procedure as below:
Create Proc dbo.GetApplicantsByIDs
#Ids NVARCHAR(MAX)
as
Select * from Applicants where ID in
(SELECT value FROM [dbo].[Split](',', #Ids)
Another solution using table variables (for the sake of it):
if exists (select table_name from information_schema.tables where table_name = 'Applicants')
drop table Applicants
go
create table Applicants (
Id int identity,
Name varchar(50)
)
go
insert Applicants (Name) values ('David')
insert Applicants (Name) values ('John')
insert Applicants (Name) values ('Scott')
insert Applicants (Name) values ('Anna')
insert Applicants (Name) values ('Esther')
go
create type IDs as table (
ID int
)
go
if exists (select routine_name from information_schema.routines where routine_name = 'GetApplicantsByIDs')
drop proc GetApplicantsByIDs
go
create proc GetApplicantsByIDs (
#IDs IDs readonly
)
as
begin
select * from Applicants A where Id in (select * from #IDs)
end
go
declare #MyIDs as IDs
insert #MyIDs values (2)
insert #MyIDs values (4)
insert #MyIDs values (1)
exec GetApplicantsByIDs #MyIDs
go
Produces:
1 David
2 John
4 Anna

Delete duplicated rows and Update references

How do I Delete duplicated rows in one Table and update References in another table to the remaining row? The duplication only occurs in the name. The Id Columns are Identity columns.
Example:
Assume we have two tables Doubles and Data.
Doubles table (
Id int,
Name varchar(50)
)
Data Table (
Id int,
DoublesId int
)
Now I Have Two entries in the Doubls table:
Id Name
1 Foo
2 Foo
And two entries in the Data Table:
ID DoublesId
1 1
2 2
At the end there should be only one entry in the Doubles Table:
Id Name
1 Foo
And two entries in the Data Table:
Id DoublesId
1 1
2 1
In the doubles Table there can be any number of duplicated rows per name (up to 30) and also regular 'single' rows.
I've not run this, but hopefully it should be correct, and close enough to the final soln to get you there. Let me know any mistakes if you like and I'll update the answer.
--updates the data table to the min ids for each name
update Data
set id = final_id
from
Data
join
Doubles
on Doubles.id = Data.id
join
(
select
name
min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
--deletes redundant ids from the Doubles table
delete
from Doubles
where id not in
(
select
min(id) as final_id
from Doubles
group by name
)
Note: I have taken the liberty to rename your Id's to DoubleID and DataID respectively. I find that eassier to work with.
DECLARE #Doubles TABLE (DoubleID INT, Name VARCHAR(50))
DECLARE #Data TABLE (DataID INT, DoubleID INT)
INSERT INTO #Doubles VALUES (1, 'Foo')
INSERT INTO #Doubles VALUES (2, 'Foo')
INSERT INTO #Doubles VALUES (3, 'Bar')
INSERT INTO #Doubles VALUES (4, 'Bar')
INSERT INTO #Data VALUES (1, 1)
INSERT INTO #Data VALUES (1, 2)
INSERT INTO #Data VALUES (1, 3)
INSERT INTO #Data VALUES (1, 4)
SELECT * FROM #Doubles
SELECT * FROM #Data
UPDATE #Data
SET DoubleID = MinDoubleID
FROM #Data dt
INNER JOIN #Doubles db ON db.DoubleID = dt.DoubleID
INNER JOIN (
SELECT db.Name, MinDoubleID = MIN(db.DoubleID)
FROM #Doubles db
GROUP BY db.Name
) dbmin ON dbmin.Name = db.Name
/* Kudos to quassnoi */
;WITH q AS (
SELECT Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS rn
FROM #Doubles
)
DELETE
FROM q
WHERE rn > 1
SELECT * FROM #Doubles
SELECT * FROM #Data
Take a look at this one, i have tried this, working fine
--create table Doubles ( Id int, Name varchar(50))
--create table Data( Id int, DoublesId int)
--select * from doubles
--select * from data
Declare #NonDuplicateID int
Declare #NonDuplicateName varchar(max)
DECLARE #sqlQuery nvarchar(max)
DECLARE DeleteDuplicate CURSOR FOR
SELECT Max(id),name AS SingleID FROM Doubles
GROUP BY [NAME]
OPEN DeleteDuplicate
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID, #NonDuplicateName
--Fetch next record
WHILE ##FETCH_STATUS = 0
BEGIN
--select b.ID , b.DoublesID, a.[name],a.id asdasd
--from doubles a inner join data b
--on
--a.ID=b.DoublesID
--where b.DoublesID<>#NonDuplicateID
--and a.[name]=#NonDuplicateName
print '---------------------------------------------';
select
#sqlQuery =
'update b
set b.DoublesID=' + cast(#NonDuplicateID as varchar(50)) + '
from
doubles a
inner join
data b
on
a.ID=b.DoublesID
where b.DoublesID<>' + cast(#NonDuplicateID as varchar(50)) +
' and a.[name]=''' + cast(#NonDuplicateName as varchar(max)) +'''';
print #sqlQuery
exec sp_executeSQL #sqlQuery
print '---------------------------------------------';
-- now move the cursor
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID ,#NonDuplicateName
END
CLOSE DeleteDuplicate --Close cursor
DEALLOCATE DeleteDuplicate --Deallocate cursor
---- Delete duplicate rows from original table
DELETE
FROM doubles
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM doubles
GROUP BY [NAME]
)
Please try and let me know if this helped you
Thanks
~ Aamod
If you are using MYSQL following worked for me. I did it for 2 steps
Step 1 -> Update all Data rows to one Double table reference (with lowest id)
Step 2 -> Delete all duplicates with keeping lowest id
Step 1 ->
update Data
join
Doubles
on Data.DoublesId = Doubles.id
join
(
select name, min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
set DoublesId = min_ids.final_id;
Step 2 ->
DELETE c1 FROM Doubles c1
INNER JOIN Doubles c2
WHERE
c1.id > c2.id AND
c1.name = c2.name;