Transform SQL Table - sql

We have a table that has the following format
RecordID FieldName FieldValue
1 Name John
1 Age 30
2 Name Alice
2 Age 40
We would like to present this as:
John 30
Alice 40
Anyone have a good solution for this?

SELECT
TN.FieldValue AS ValueName
, TV.FieldValue AS ValueAge
FROM dbo.Table1 TN
INNER JOIN dbo.Table1 TV ON TN.RecordID = TV.RecordID
AND TN.FieldName = 'Name'
AND TV.FieldName = 'Age'

Why didn't anybody use pivot?
declare #a TABLE(RecordId int, FieldName varchar(20), FieldValue varchar(20))
insert into #a select 1, 'Name', 'John'
insert into #a select 1, 'Age', '30'
insert into #a select 2, 'Name', 'Alice'
insert into #a select 2, 'Age', '40'
select *
from #a a pivot (max(FieldValue) for FieldName in (Name,Age)) p

declare #a TABLE(RecordId int, FieldName varchar(20), FieldValue varchar(20))
insert into #a select 1, 'Name', 'John'
insert into #a select 1, 'Age', '30'
insert into #a select 2, 'Name', 'Alice'
insert into #a select 2, 'Age', '40'
select
records.RecordId
, name.fieldvalue [Name]
, age.fieldvalue [Age]
from
(select distinct recordid from #a) records
inner join #a name on records.recordid = name.recordid and name.fieldname = 'Name'
inner join #a age on records.recordid = age.recordid and age.fieldname = 'Age'

This ain't pretty (but nor's the data), but this will work if your column names are known when you write the query:
SELECT
RecordId,
group_concat( if( FieldName = 'name', FieldValue, '' ) SEPARATOR '' ) AS person_name,
group_concat( if( FieldName = 'age', FieldValue, '' ) SEPARATOR '' ) AS person_age
FROM test_table
GROUP BY RecordId
(works in MySQL 5.0)
You should also use CAST to get the fields to the correct type
If you don't know the fields, you'll need to (programatically) do a select distinct FieldName beforehand in order to build your query
I've a feeling the the Drupal Content Creation Kit (CCK) does something rather similar to this

Related

Want to compare 4 different columns with the result of CTE

I have created a CTE (common table Expression) as follows:
DECLARE #N VARCHAR(100)
WITH CAT_NAM AS (
SELECT ID, NAME
FROM TABLE1
WHERE YEAR(DATE) = YEAR(GETDATE())
)
SELECT #N = STUFF((
SELECT ','''+ NAME+''''
FROM CAT_NAM
WHERE ID IN (20,23,25,30,37)
FOR XML PATH ('')
),1,1,'')
The result of above CTE is 'A','B','C','D','F'
Now I need to check 4 different columns CAT_NAM_1,CAT_NAM_2,CAT_NAM_3,CAT_NAM_4 in the result of CTE and form it as one column like follow:
Select
case when CAT_NAM_1 in (#N) then CAT_NAM_1
when CAT_NAM_2 in (#N) then CAT_NAM_2
when CAT_NAM_3 in (#N) then CAT_NAM_3
when CAT_NAM_4 in (#N) then CAT_NAM_4
end as CAT
from table2
When I'm trying to do the above getting error please help me to do.
If my approach is wrong help me with right one.
I am not exactly sure what you are trying to do, but if I understand the following script shows one possible technique. I have created some table variables to mimic the data you presented and then wrote a SELECT statement to do what I think you asked (but I am not sure).
DECLARE #TABLE1 AS TABLE (
ID INT NOT NULL,
[NAME] VARCHAR(10) NOT NULL,
[DATE] DATE NOT NULL
);
INSERT INTO #TABLE1(ID,[NAME],[DATE])
VALUES (20, 'A', '2021-01-01'), (23, 'B', '2021-02-01'),
(25, 'C', '2021-03-01'),(30, 'D', '2021-04-01'),
(37, 'E', '2021-05-01'),(40, 'F', '2021-06-01');
DECLARE #TABLE2 AS TABLE (
ID INT NOT NULL,
CAT_NAM_1 VARCHAR(10) NULL,
CAT_NAM_2 VARCHAR(10) NULL,
CAT_NAM_3 VARCHAR(10) NULL,
CAT_NAM_4 VARCHAR(10) NULL
);
INSERT INTO #TABLE2(ID,CAT_NAM_1,CAT_NAM_2,CAT_NAM_3,CAT_NAM_4)
VALUES (1,'A',NULL,NULL,NULL),(2,NULL,'B',NULL,NULL);
;WITH CAT_NAM AS (
SELECT ID, [NAME]
FROM #TABLE1
WHERE YEAR([DATE]) = YEAR(GETDATE())
AND ID IN (20,23,25,30,37,40)
)
SELECT CASE
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_1) THEN CAT_NAM_1
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_2) THEN CAT_NAM_2
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_3) THEN CAT_NAM_3
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_4) THEN CAT_NAM_4
ELSE '?' -- not sure what you want if there is no match
END AS CAT
FROM #TABLE2;
You can do a bit of set-based logic for this
SELECT
ct.NAME
FROM table2 t2
CROSS APPLY (
SELECT v.NAME
FROM (VALUES
(t2.CAT_NAM_1),
(t2.CAT_NAM_2),
(t2.CAT_NAM_3),
(t2.CAT_NAM_4)
) v(NAME)
INTERSECT
SELECT ct.NAM
FROM CAT_NAM ct
WHERE ct.ID IN (20,23,25,30,37)
) ct;

Convert Table to Specific Column Wise

I have a table like this. How can I convert to this format?
DECLARE #A TaBLE (KeyValue INT, Name VARCHAR(50), Value VARCHAR(512))
INSERT INTO #A
VALUES (0, 'AccountID', '192507'), (0, 'member_id', '999159'),
(0, 'firstname', 'Test1'), (0, 'lastname', 'Last1'),
(1, 'AccountID', '192508'), (1, 'member_id', '999160'),
(1, 'firstname', 'Test2'), (1, 'lastname', 'Last2')
SELECT * FROM #A
I have table rows for this model:
KeyValue Name Value
-----------------------------------
0 AccountID 192507
0 member_id 999159
0 firstname Test1
0 lastname Last1
1 AccountID 192508
1 member_id 999160
1 firstname Test2
1 lastname Last2
My expected output is:
AccountID member_id firstname lastname
--------------------------------------------
192507 999159 Test1 Last1
192508 999160 Test2 Last2
I tried this code But it didn't work
select *
from
(
select Name,value
from #A
) d
pivot
(
MAX(value)
for Name in (AccountID,member_id,firstname,lastname)
) piv;
Try this below logic-
DEMO HERE
SELECT
MAX(CASE WHEN Name = 'AccountID' THEN Value ELSE NULL END) AccountID,
MAX(CASE WHEN Name = 'member_id' THEN Value ELSE NULL END) member_id ,
MAX(CASE WHEN Name = 'firstname' THEN Value ELSE NULL END) firstname ,
MAX(CASE WHEN Name = 'lastname' THEN Value ELSE NULL END) lastname
FROM #A
GROUP BY KeyValue
You can get the desired result by using PIVOT. In your query you just need to select all the columns, like below.
SELECT AccountID, member_id, firstname, lastname
FROM
(
select * from #A
) d
PIVOT
(
MAX(value)
FOR Name IN (AccountID, member_id, firstname, lastname)
) piv;
You can run the test here.
In the temp table, you should select all useful information like this
select AccountID, member_id, firstname, lastname
from
(
select * from #A -- instead of `select Name,value`
) d
pivot
(
MAX(value)
for Name in (AccountID,member_id,firstname,lastname)
) piv;
Result here

Displaying multiple select in a single cell

Please help me to solve the following issue .
consider i have two tables in a Database
1.employee 2.Details
In employee table data will be
eid ename level
1 x 9th
2 y 10th
In Address Table data will be
AId eid location Adreess_type
1 1 india permananet
2 1 US Temporary
3 2 Japan permananet
4 2 China Temporary
I need output in the below format
eid ename fulllocation
1 X INDIA -US
2 y Japan-CHINA
Try this:
SELECT
e.eid,
e.name,
GROUP_CONCAT(a.location SEPARATOR '-') AS fulllocation
FROM
employee as e
INNER JOIN address as a
ON e.eid = a.eid
GROUP BY
e.eid
select employee.eid, employee.ename, t.fulllocation
from employee
inner join (select eid, group_concat(location SEPARATOR '-') as fulllocation from Address group by eid) t
on employee.eid = t.eid
Consider that GROUP_CONCAT have some limitations, what is this and how can change (if needed) it? please check documentation for this.
DECLARE #t1 TABLE
(
eid int NOT NULL,
ename varchar(50),
level varchar(50)
)
DECLARE #t2 TABLE
(
aid int NOT NULL,
eid int,
location varchar(50),
address_type varchar(50)
)
INSERT INTO #t1 SELECT 1, 'x', '9th'
INSERT INTO #t1 SELECT 2, 'y', '10th'
INSERT INTO #t2 SELECT 1, 1, 'india', 'permanent'
INSERT INTO #t2 SELECT 2, 1, 'US', 'temporary'
INSERT INTO #t2 SELECT 3, 2, 'Japan', 'permanent'
INSERT INTO #t2 SELECT 4, 2, 'China', 'temporary'
SELECT * FROM #t1
SELECT * FROM #t2
SELECT t1.eid, t1.ename, t2.fullLocation
FROM #t1 AS t1
INNER JOIN (
SELECT eid, COUNT(*) AS noofrecs
, fullLocation = LTRIM(RTRIM(ISNULL(STUFF(
(
SELECT DISTINCT '-' + CAST(t2.location as nvarchar(max))
FROM #t2 t2
WHERE t1.eid = t2.eid
FOR XML PATH (''), TYPE).value('.', 'nvarchar(max)'
), 1, 1, ''), '')))
FROM #t2 as t1
GROUP BY eid
) AS t2
ON t1.eid = t2.eid
DECLARE #t1 TABLE
(
eid int NOT NULL,
ename varchar(50),
level varchar(50)
)
DECLARE #t2 TABLE
(
aid int NOT NULL,
eid int,
location varchar(50),
address_type varchar(50)
)
INSERT INTO #t1 SELECT 1, 'x', '9th'
INSERT INTO #t1 SELECT 2, 'y', '10th'
INSERT INTO #t2 SELECT 1, 1, 'india', 'permanent'
INSERT INTO #t2 SELECT 2, 1, 'US', 'temporary'
INSERT INTO #t2 SELECT 3, 2, 'Japan', 'permanent'
INSERT INTO #t2 SELECT 4, 2, 'China', 'temporary'
SELECT * FROM #t1
SELECT * FROM #t2
SELECT b.eid,b.ename
, STUFF((SELECT '_ ' + a.location FROM #t2 A
Where A.eid=B.eid FOR XML PATH('')),1,1,'') As fulllocation
From #t1 B
Group By b.eid,b.ename
In order to preserve the order of the locations, you could work along
SELECT
e.eid
, e.ename
, CONCAT_WS('-', p.location, t.location) AS fulllocation
FROM Employee e
JOIN Address p
ON e.eid = p.eid
AND p.address_type = 'permananet'
JOIN Address t
ON e.eid = t.eid
AND t.address_type = 'Temporary'
;
See it in action: SQL Fiddle.
Please comment if and as this requrires adjustment / further detail.

Rows to single cell

I would like to get the desired output marked in green
the data points for each id get put into a single cell
Basically take all the events that have happened with A and attach it in the same order
Use Stuff Function:
DECLARE #tblTest AS Table(
ID INT,
EVENT VARCHAR(5)
)
INSERT INTO #tblTest VALUES
(1,'A'),
(1,'A'),
(1,'C'),
(2,'A'),
(2,'B'),
(2,'C')
SELECT DISTINCT
T1.ID,
STUFF
(
(SELECT '' + convert(varchar(10), T2.EVENT, 120)
FROM #tblTest T2
where T1.ID = T2.ID
FOR XML PATH (''))
, 1, 0, '') AS EVENT
FROM #tblTest T1
You can use FOR XML:
SELECT DISTINCT
ID,
(SELECT [EVENT] +''
FROM YourTable
WHERE ID = y.ID
FOR XML PATH('')
) as [EVENT]
FROM YourTable y
Output:
ID EVENT
1 AABCD
2 AABBCC
You can use UDF to do so as follows:
CREATE TABLE t(
id INT,
col CHAR(1)
);
INSERT INTO t VALUES (1,'a');
INSERT INTO t VALUES (1,'b');
INSERT INTO t VALUES (1,'c');
INSERT INTO t VALUES (1,'d');
INSERT INTO t VALUES (2,'e');
INSERT INTO t VALUES (2,'f');
INSERT INTO t VALUES (3,'g');
INSERT INTO t VALUES (4,'h');
The UDF (User defined function) -
USE [t]
GO
CREATE FUNCTION dbo.ConcatenateCols(#Id INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #RtnStr VARCHAR(MAX)
SELECT #RtnStr = COALESCE(#RtnStr + '','') + col
FROM dbo.t
WHERE id = #Id AND col > ''
RETURN #RtnStr
END
GO
Finally the query and result:
SELECT id, dbo.ConcatenateCols(id) AS Cols -- UDF - ConcatenateCols(id)
FROM t GROUP BY Id
CREATE TABLE #temp(Id INt,Event Nvarchar(25))
INSERT INTO #temp
SELECT 1,
'A'
UNION ALL
SELECT 1,
'A'
UNION ALL
SELECT 1,
'B'
UNION ALL
SELECT 1,
'C'
UNION ALL
SELECT 1,
'D'
UNION ALL
SELECT 2,
'A'
UNION ALL
SELECT 2,
'A'
UNION ALL
SELECT 2,
'B'
UNION ALL
SELECT 2,
'B'
UNION ALL
SELECT 2,
'C'
UNION ALL
SELECT 2,
'C'
SELECT DISTINCT ID,
(SELECT [EVENT] +''
FROM #temp
WHERE ID = y.ID
FOR XML PATH('') ) AS [EVENT]
FROM #temp y

SQL Stored Procedure adding to statement

Issue:
I want to pass a value say #Test into a stored procedure and I know that when #Test is certain values all is good. However I want to filter several values in the Table/Gridview under one #Test value.
i.e. User searches for "Red" I want to show "Red" "Pink" etc...
I am sure there must be hunderds of examples but I have searched and not found them. I have tried BEGIN and also IF statements.
If .net I would add a If #Text = 'Pink' Then
sql= sql & ... statement...
So far I have...
SELECT * FROM TblColours
WHERE
Room LIKE '%' + #sRoom + '%'
or Colours LIKE '%' + #sColours + '%'
IF #sColours = 'Pink'
or Colours = 'Red'
or Colours = 'Shade of Pink'
END
I agree with Andrew, that it would be much easier to store the colours and their groupings in separate tables - it might look something like the below (two new tables, #Colours and #Colourgroups are used).
-- SETUP TABLES AND VALUES
----------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb.dbo.#Colours') IS NOT NULL DROP TABLE #Colours
IF OBJECT_ID('tempdb.dbo.#TblColours') IS NOT NULL DROP TABLE #TblColours
IF OBJECT_ID('tempdb..#ColourGroups') IS NOT NULL DROP TABLE #ColourGroups
CREATE TABLE #Colours
( Id INT NOT NULL PRIMARY KEY CLUSTERED
,GroupId INT NOT NULL
,Name VARCHAR(50) NOT NULL)
CREATE TABLE #ColourGroups
( Id INT NOT NULL PRIMARY KEY CLUSTERED
,Name VARCHAR(50) NOT NULL)
CREATE TABLE #TblColours
( Room VARCHAR(50) NOT NULL
,ColourId INT NOT NULL)
INSERT #Colours
SELECT * FROM
(SELECT 1 AS Id, 1 AS GroupId, 'Red' AS Name UNION
SELECT 2 AS Id, 2 AS GroupId, 'Orange' AS Name UNION
SELECT 3 AS Id, 3 AS GroupId, 'Yellow' AS Name UNION
SELECT 4 AS Id, 1 AS GroupId, 'Pink' AS Name UNION
SELECT 5 AS Id, 1 AS GroupId, 'Scarlet' AS Name UNION
SELECT 6 AS Id, 1 AS GroupId, 'Rose' AS Name) AS SomeRandomColours
ORDER BY Id
INSERT #ColourGroups
SELECT * FROM
(SELECT 1 AS Id, 'Red' AS Name UNION
SELECT 2 AS Id, 'Orange' AS Name UNION
SELECT 3 AS Id, 'Yellow' AS Name) AS SomePossibleGroups
ORDER BY Id
INSERT #TblColours Values ('Gail''s Bedroom', 6)
INSERT #TblColours Values ('The Horrid Bathroom', 2)
INSERT #TblColours Values ('The Main DrawingRoom', 5)
INSERT #TblColours Values ('Paul and Barbara''s Bedroom', 4)
INSERT #TblColours Values ('Paul''s Study', 1)
----------------------------------------------------------------------------------------------
-- Include Derived colour working back from the group if you want to find all the colours in
-- the same group as your search.
DECLARE
#sRoom VARCHAR(50) = 'Barbara'
,#sColours VARCHAR(50) = 'Pink'
SELECT DISTINCT
Room.Room
,Colour.Name
FROM #TblColours AS Room
INNER JOIN #Colours AS Colour ON Room.ColourId = Colour.Id
INNER JOIN #ColourGroups AS ColourGroup ON Colour.GroupId = ColourGroup.Id
INNER JOIN #Colours AS DerivedColour ON ColourGroup.Id = DerivedColour.GroupId
WHERE
Room LIKE '%' + #sRoom + '%'
OR Colour.Name = #sColours
OR ColourGroup.Name = #sColours
OR DerivedColour.Name = #sColours