How to Pivot Column Headers in Rows - sql

I have table as following
ID FName LName
r1 Tom Patrik
r2 Jerry Blaku
r1 Ethan Lie
I would like something as following
ID r1 r2 r1
FName Tom Jerry Ethan
LName Patrik Blaku Lie
NOTE THAT VALUES IN ID ARE NOT DISTINCT....!!
Is it possible to achieve this using sql Server Pivot(Or any) command,
If yes I will really appreciate TSQL for that

I am sure there are better ways of doing this. But since you are trying to pivot multiple columns here is an ugly solution:
create table #temp
(
id int,
fname varchar(50),
lname varchar(50)
)
insert into #temp values(1, 'Tom', 'Patrik')
insert into #temp values(2, 'Jerry', 'Blaku')
SELECT 'fname', P.Tom as '1', P.Jerry as '2'
FROM
(
SELECT fname
FROM #temp
) I
PIVOT
(
min(fname)
FOR [fname] IN ([Tom], [Jerry])
) as P
UNION
SELECT 'lname', P.Patrik as '1', P.Blaku as '2'
FROM
(
SELECT lname
FROM #temp
) I
PIVOT
(
min(lname)
FOR [lname] IN ([Patrik], [Blaku])
) as P
drop table #temp

Related

T-SQL: convert columns to rows and insert/update another table

Looking for non fancy, easily debugable for junior developer solution...
In SQL Server 2008 R2, I have to update data from #data table to #tests table in desired format. I am not sure how I would archive result using T-SQL query?
NOTE: temp tables have only 3 columns for sample purpose only but real table have more than 50 columns for each set.
Here is what my tables look like:
IF OBJECT_ID('tempdb..#tests') IS NOT NULL
DROP TABLE #tests
GO
CREATE TABLE #tests
(
id int,
FirstName varchar(100),
LastName varchar(100),
UniueNumber varchar(100)
)
IF OBJECT_ID('tempdb..#data') IS NOT NULL
DROP TABLE #data
GO
CREATE TABLE #data
(
id int,
FirstName1 varchar(100),
LastName1 varchar(100),
UniueNumber1 varchar(100),
FirstName2 varchar(100),
LastName2 varchar(100),
UniueNumber2 varchar(100),
FirstName3 varchar(100),
LastName3 varchar(100),
UniueNumber3 varchar(100),
FirstName4 varchar(100),
LastName4 varchar(100),
UniueNumber4 varchar(100),
FirstName5 varchar(100),
LastName5 varchar(100),
UniueNumber5 varchar(100),
FirstName6 varchar(100),
LastName6 varchar(100),
UniueNumber6 varchar(100),
FirstName7 varchar(100),
LastName7 varchar(100),
UniueNumber7 varchar(100)
)
INSERT INTO #data
VALUES (111, 'Tom', 'M', '12345', 'Sam', 'M', '65432', 'Chris', 'PATT', '54656', 'Sean', 'Meyer', '865554', 'Mike', 'Max', '999999', 'Tee', 'itc', '656546444', 'Mickey', 'Mul', '65443231')
INSERT INTO #data
VALUES (222, 'Kurr', 'P', '22222', 'Yammy', 'G', '33333', 'Saras', 'pi', '55555', 'Man', 'Shey', '666666', 'Max', 'Dopit', '66666678', '', '', '', '', '', '')
INSERT INTO #data
VALUES (333, 'Mia', 'K', '625344', 'Tee', 'TE', '777766', 'david', 'mot', '4444444', 'Jeff', 'August', '5666666', 'Mylee', 'Max', '0000000', '', '', '', 'Amy', 'Marr', '55543444')
SELECT *
FROM #data
I want to insert/update data into #tests table from #data table.
Insert data into #tests table if id and UniqueNumber combination does not exists from #data table. If combination exists then update data into #tests table from #data table
This is desired output into #tests table
Here is an option that will dynamically UNPIVOT your data without using Dynamic SQL
To be clear: UNPIVOT would be more performant, but you don't have to enumerate the 50 columns.
This is assuming your columns end with a NUMERIC i.e. FirstName##
Example
Select ID
,FirstName
,LastName
,UniueNumber -- You could use SSN = UniueNumber
From (
SELECT A.ID
,Grp
,Col = replace([Key],Grp,'')
,Value
FROM #data A
Cross Apply (
Select [Key]
,Value
,Grp = substring([Key],patindex('%[0-9]%',[Key]),25)
From OpenJson( (Select A.* For JSON Path,Without_Array_Wrapper ) )
) B
) src
Pivot ( max(Value) for Col in ([FirstName],[LastName],[UniueNumber]) ) pvt
Order By ID,Grp
Results
UPDATE XML Version
Select ID
,FirstName
,LastName
,UniueNumber
From (
SELECT A.ID
,Grp = substring(Item,patindex('%[0-9]%',Item),50)
,Col = replace(Item,substring(Item,patindex('%[0-9]%',Item),50),'')
,Value
FROM #data A
Cross Apply ( values (convert(xml,(Select A.* for XML RAW)))) B(XData)
Cross Apply (
Select Item = xAttr.value('local-name(.)', 'varchar(100)')
,Value = xAttr.value('.','varchar(max)')
From B.XData.nodes('//#*') xNode(xAttr)
) C
Where Item not in ('ID')
) src
Pivot ( max(Value) for Col in (FirstName,LastName,UniueNumber) ) pvt
Order By ID,Grp
One way is to query each group of columns separately and UNION the results
SELECT
id int,
FirstName1 as FirstName,
LastName1 as LastName,
UniueNumber1 AS SSN
FROM #data
UNION
SELECT
id int,
FirstName2 as FirstName,
LastName2 as LastName,
UniueNumber2 AS SSN
FROM #data
UNION
...
There's not a way to cleanly "loop through" the 7 groups of columns - you'll spend more time building a loop to create the query dynamically than just copying and pasting the query 6 times and changing the number.
Of course, it's best to avoid the type of structure you have in #data now if at all possible.

Searching a column value that has couple records with some different specified values

I have a database:
|id|surname|name
| 1|Smith |John
| 2|Smith |Mike
| 3|Smith |Bob
| 4|Knope |John
| 5|Knope |Mike
| 6|Knope |Dick
| 7|Pratt |John
| 8|Pratt |Jill
| 9|Pratt |James
and I want to find a family name that has in it John, Mike and Bob. I want it to return Smith. Or I want to search for a family that has in it John and Mike and I want it to return Smith and Knope. How can I do that?
the results that I want to get are above but here's the same with nicer form:
I'm looking for family that has Jon, Mike, Bob. I want to get:
|surname|
|Smith |
Then I want to look for John and Mike only and I want to get:
|surname|
|Smith |
|Knope |
Based on your explantions you can do something like this:
declare #table table (it int, surename varchar(50),name1 varchar(50))
insert into #table
values
(1,'Smith','John'),
(2,'Smith','Mike'),
(3,'Smith','Bob' ),
(4,'Knope','John'),
(5,'Knope','Mike'),
(6,'Knope','Dick'),
(7,'Pratt','John'),
(8,'Pratt','Jill'),
(9,'Pratt','James')
select * from #table
where name1 in ('john','mike','bob') and surename = 'smith'
union
select * from #table
where name1 in('john','mike') and surename in ('smith','knope')
Result
Your input has dynamically multiple values. Thus, I will assume you have put all of the names you want the family to include in a table #i with field "name". Then, you want all families for which no name specified in your input is missing.
select *
from (select distinct surename from yourtable)surnames
where not exists
(
select 1 from #i
where not exists
(
select 1
from yourtable t
where
t.surename=surnames.surename
and #i.name=t.name
)
)
This works in SQL Server - written before your question was tagged with PostgreSQL.
Set up the test data:
DECLARE #Names TABLE (ID INTEGER IDENTITY, Surname VARCHAR(50), Forenames VARCHAR(50));
INSERT
#Names (Surname, Forenames)
VALUES
('Smith', 'John'),
('Smith', 'Mike'),
('Smith', 'Bob' ),
('Knope', 'John'),
('Knope', 'Mike'),
('Knope', 'Dick'),
('Pratt', 'John'),
('Pratt', 'Jill'),
('Pratt', 'James');
Declare a table variable containing the forenames you'd like to match. This acts as a parameter, so you should edit the values we insert to test the results:
DECLARE #ForenamesToSearch TABLE (Forenames VARCHAR(50));
INSERT
#ForenamesToSearch
VALUES
('John')
, ('Mike')
, ('Bob');
Finally we use GROUP BY and HAVING COUNT to ensure the number of names matches exactly.
SELECT
Surname
FROM
(SELECT DISTINCT Forenames, Surname FROM #Names) Names
INNER JOIN #ForenamesToSearch Forenames ON Names.Forenames = Forenames.Forenames
GROUP BY
Surname
HAVING
COUNT(1) = (SELECT COUNT(1) FROM #ForenamesToSearch);
Probably not the best way to do this but you can try the following for Postgresql:
select *
from
(
select
concat(',' , string_agg(name1,',') , ',') as X,
surname
from
table_name as A
group BY
surname
) As B
Where B.X like '%,John,%' And B.X like '%,Mike,%' And B.X like '%,Bob,%';
SQLFIDDLE DEMO
The following is for SQL server:
select * from
(
select
', ' + STUFF((SELECT ', ' + name1 FROM table_name WHERE surname = A.surname FOR XML PATH('')),1,2,'') + ',' as X,
surname
from
table_name as A
group BY
surname
) as B
Where B.X like '%, John,%' And B.X like '%, Mike,%' And B.X like '%, Bob,%';
SQLFIDDLE DEMO

SQL Server Compare rows of one table with all rows of other table

I have 2 tables which contains firstname, surname,dob.
First table has datatype as varchar for all columns and second table is varchar(50),varchar(50),datetime datatype.
Ex:
1st table
fname surname dob
a b 04/12/1948
a b 05/08/1984
2nd table
fname surname dob
a b 05/08/1984
a b 04/12/1948
when i do Intersect is not matching the decors (possibly b'ze of datatype)
and except give me result.
Is there any way to select all record from table 1 with matching records of table 2.
Any help much apprecciated
Both EXCEPT and INTERSECT work:
Declare #tblA AS TABLE(
FirstName VARCHAR(50),
SurName VARCHAR(50),
Dob VARCHAR(50)
)
Declare #tblB AS TABLE(
FirstName VARCHAR(50),
SurName VARCHAR(50),
Dob Date
)
INSERT INTO #tblA VALUES
('a','b','04/12/1948'),
('a','b','05/08/1948')
INSERT INTO #tblB VALUES
('a','b','04/12/1948'),
('a','b','05/09/1948')
SELECT
*
FROM #tblA
INTERSECT
SELECT
*
FROM #tblB
SELECT
*
FROM #tblA
EXCEPT
SELECT
*
FROM #tblB
Output:
SELECT fname, surname, CAST(dob AS DATETIME) AS dob FROM table1
INTERSECT
SELECT fname, surname, dob FROM table2
Use this query.
Select * from table1 as a
Inner join table2 as b
on a.fname = b.fname and a.surname = b.surname and cast(a.dob as date)=b.dob
SELECT * FROM #Table1 JOIN #Table2 ON #Table2.dob = CONVERT(DATETIME,#Table1.dob,101)

Query to Append a Number to a Record it it finds a duplicate

I have an sql table with the following fields: Letter, Number, Result
Title Name Result
Mr Mark
Mr Mark
Mr Luke
Mr John
Mr John
I need to create an update query to have the result as
Title Name Result
Mr Mark MrMark
Mr Mark MrMark2
Mr Luke MrLuke
Mr John MrJohn
Mr John MrJohn2
Note that the second and the fifth record had a number 2 appended since it already found the same record (same Title and Name) previously.
Please help.
If it is MS SQL, try using ROW_NUMBER and PARTITION BY?
DECLARE #temp TABLE (Title NVARCHAR(200), Name NVARCHAR(200), Result NVARCHAR(200));
INSERT #temp
SELECT 'Mr', 'Mark', NULL
UNION ALL
SELECT 'Mr', 'Mark', NULL
UNION ALL
SELECT 'Mr', 'Luke', NULL
UNION ALL
SELECT 'Mr', 'John', NULL
UNION ALL
SELECT 'Mr', 'John', NULL
SELECT * FROM #temp
DECLARE #tempWithOrdering TABLE (RowNum INT, Title NVARCHAR(200), Name NVARCHAR(200), Result NVARCHAR(200));
INSERT #tempWithOrdering
SELECT ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Title ), Title, Name, Result FROM #temp
SELECT * FROM #tempWithOrdering
SELECT
Title,
Name,
Result = (
SELECT TOP(1) Name +
CASE RowNum
WHEN t1.RowNum THEN ''
ELSE CAST(t1.RowNum AS NVARCHAR(12))
END
FROM #tempWithOrdering
WHERE Name = t1.Name
)
FROM #tempWithOrdering t1
Assuming you are using sql server and the duplicate is on the field 'Name' .Try this.
Use Analytic fn ROW_NUMBER() ;
If it is Oracle use || instead of +
WITH TEMP AS
(
SELECT Title , Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY bill_period) AS RK
FROM TABLE1
)
SELECT Title , Name,Title + Name +RK FROM TEMP;

Path enumeration model, how to get superiors?

Consider the table data below:
emp_name VARCHAR(25), path VARCHAR(150)
Albert /Albert
John /Albert/John
Chuck /Albert/Chuck
Tom /Albert/John/Tom
Frank /Frank
I want to get a list of superiors of Tom:
John
Albert
(can include Tom)
Is it possible to do with without splitting the path and then using a sequence table (only way I found)?
DB is Sql server 2008 R2
You can use a recursive CTE to split the hierarchy string value.
declare #T table
(
ID int identity,
emp_name varchar(25),
[path] varchar(150)
)
insert into #T values
('Albert', 'Albert'),
('John', 'Albert/John'),
('Chuck', 'Albert/Chuck'),
('Tom', 'Albert/John/Tom'),
('Frank', 'Frank')
declare #EmpName varchar(25) = 'Tom'
;with cte(Sort, P1, P2, [path]) as
(
select 1,
1,
charindex('/', [path]+'/', 1),
[path]
from #T
where emp_name = #EmpName
union all
select Sort+1,
P2+1,
charindex('/', [path]+'/', C.P2+1),
[path]
from cte as C
where charindex('/', [path]+'/', C.P2+1) > 0
)
select substring([path], P1, P2-P1)
from cte
order by Sort
Result:
(No column name)
Albert
John
Tom
Test the query here: https://data.stackexchange.com/stackoverflow/q/101383/
Another thing you can try
select T2.emp_name
from #T as T1
inner join #T as T2
on '/'+T1.[path]+'/' like '%/'+T2.emp_name+'/%' and
T2.emp_name <> #EmpName
where T1.emp_name = #EmpName
https://data.stackexchange.com/stackoverflow/q/101518/get-hierarchy-with-join-using-like