How to convert column into row with header sql - sql

Note : i need the record like this
Scode value
BR 10
DL 7

One method is union all:
select 'br', br from t union all
select 'dl', dl from t union all
select 'AP', ap from t;
In a database that supports lateral joins, I would recommend something like this:
select v.*
from t cross apply
(values ('br', br), ('dl', dl), ('AP', ap)
) v(col, val);

use this query, it is dynamic and working.
CREATE TABLE [dbo].[temp](
[br] [int] NULL,
[dl] [int] NULL,
[ap] [int] NULL,
[hp] int null,
[kl] int null,
[mh] int null,
[py] int null
)
insert into temp values(10,7,7,7,8,8,0)
--Drop Table if exists #temp2
--drop table if exists #temp
create table #temp2(id int identity primary key,Scode varchar(10),value int)
declare #col varchar(max),#count int,#intcount int=1,#strquery varchar(max),#id int
select ROW_NUMBER() over (order by column_id) as RN,name into #temp from sys.columns where object_id=OBJECT_ID('temp')
select #count=count(1) from #temp
while(#intcount<=#count)
begin
set #strquery=''
set #col=''
set #id=0
select #col=name from #temp where RN=#intcount
set #strquery='select '+#col+' from temp'
insert into #temp2(value)
exec(#strquery)
select #id=SCOPE_IDENTITY()
update #temp2 set [Scode]=#col where id=#id
set #intcount=#intcount+1
end
select * from temp
select Scode,value from #temp2

Please go on this link and See the simple solution my problem is Solve.
https://www.codeproject.com/Answers/5259227/Convert-column-into-row-with-header-in-SQL#answer1

You could also use CROSS APPLY with UNION ALL to convert the columns:
select id, br,
dl,
ap
from yourtable
cross apply
(
select 'br', Indicator1 union all
select 'dl', Indicator2 union all
select 'ap', Indicator3
) c (indicatorname, indicatorvalue);

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;

SQL Server stored procedure store 2 table variable in 1 table with from and to values

I have this table stored in variable #oldValues and #newValues:
The two tables above will contain 1 row maximum. My goal is to insert this to a new table JSON TABLE:
DECLARE #jsonTable TABLE
(
[Field] nvarchar(max),
[From] nvarchar(max),
[To] nvarchar(max)
);
and store the from to values from old and new variable
Output must be like this:
[Field] [From] [To] // this is a column name
------------------------------------
CommitteeID 1 1
CommitteeName Test Test2
CommitteeMemberID 1 3
How can I achieve that?
Thanks in advance
It can be plain
select 'CommitteeId' [Field], (select cast(CommitteeId as varchar(max)) from #oldValues) [From], (select cast(CommitteeId as varchar(max)) from #newValues)[To]
union all
select 'CommitteeName', (select CommitteeName from #oldValues), (select CommitteeName from #newValues)
union all
select 'CommitteeId', (select cast(CommitteeMemberId as varchar(max)) from #oldValues), (select cast(CommitteeMemberId as varchar(max)) from #newValues)
If you have only one row:
select v.*
from #oldValues ov cross join
#newValues nv outer apply
(values ('CommitteeId', ov.CommitteeId, nv.CommitteeId),
('CommitteeName', ov.CommitteeName, nv.CommitteeName),
('CommitteeMemberID', ov.CommitteeMemberID, nv.CommitteeMemberID)
) v(field, [from], [to]);
Note: This assumes that the types for the values are all compatible. Otherwise, you may need to convert/cast values to strings.
EDIT:
To be explicit, the casts are:
select v.*
from #oldValues ov cross join
#newValues nv outer apply
(values ('CommitteeId', cast(ov.CommitteeId as nvarchar(255)), cast(nv.CommitteeId as nvarchar(255))),
('CommitteeName', cast(ov.CommitteeName as nvarchar(255)), cast(nv.CommitteeName as nvarchar(255))),
('CommitteeMemberID', cast(ov.CommitteeMemberID as nvarchar(255)), cast(nv.CommitteeMemberID as nvarchar(255)))
) v(field, [from], [to]);
I think UNPIVOT operator most proper solution for the need.
For UNPIVOT operation all column types should be same, that's why we cast all column type to the same.
DECLARE #oldValues as TABLE (CommitteeID INT, CommitteeName VARCHAR(20), CommitteeMemberID INT)
INSERT INTO #oldValues VALUES (1,'Test',1)
DECLARE #newValues as TABLE (CommitteeID INT, CommitteeName VARCHAR(20), CommitteeMemberID INT)
INSERT INTO #newValues VALUES (1,'Test2',3)
DECLARE #jsonTable TABLE
(
[Field] nvarchar(max),
[From] nvarchar(max),
[To] nvarchar(max)
);
;WITH FromTable AS (
SELECT [Field] , [From]
FROM (SELECT CAST(CommitteeID AS VARCHAR(255)) CommitteeID,
CAST(CommitteeName AS VARCHAR(255)) CommitteeName,
CAST(CommitteeMemberID AS VARCHAR(255)) CommitteeMemberID
FROM #oldValues) p
UNPIVOT ( [From] FOR [Field]
IN ( CommitteeID , CommitteeName , CommitteeMemberID)) as UNPVT
)
, ToTable AS (
SELECT [Field] , [To]
FROM (SELECT CAST(CommitteeID AS VARCHAR(255)) CommitteeID,
CAST(CommitteeName AS VARCHAR(255)) CommitteeName,
CAST(CommitteeMemberID AS VARCHAR(255)) CommitteeMemberID
FROM #newValues) p
UNPIVOT ( [To] FOR [Field]
IN ( CommitteeID , CommitteeName , CommitteeMemberID)) as UNPVT
)
SELECT F.*, T.[To] FROM FromTable F FULL JOIN ToTable T ON F.[Field] = T.[Field]
New columns can be easily added to SELECT and IN part of the query.
For easily determine missing column I used FULL JOIN

Using a recursive CTE in a view

Having a typical parent/child hierarchy table it's a common thing to query it using Common Table Expression:
with CTE as (
select Id, ProviderId, ConsumerId
from T1
where ProviderId in (2, 3, 9)
union all
select T1.Id, T1.ProviderId, T1.ConsumerId
from T1
join CTE on C.ProviderId = CTE.ConsumerId
)
select * from CTE
Is it possible to create a view based on this query so that one can do:
select * from MagicView where ProviderId in (2,3,9)
In other words, can we somehow extract parameters from the anchor part of the CTE to create a generic view?
Create a TVF:
CREATE FUNCTION my_function (
#ProviderId int
)
RETURNS #ProviderTable TABLE
(
Id int NULL,
ProviderId int NULL,
ConsumerId int NULL
)
AS
BEGIN
WITH cte AS (
SELECT Id,
ProviderId,
ConsumerId
FROM T1
WHERE ProviderId in (#ProviderId)
UNION ALL
SELECT t.Id,
t.ProviderId,
t.ConsumerId
FROM T1 t
INNER JOIN cte c
ON t.ProviderId = c.ConsumerId
)
INSERT INTO #ProviderTable
SELECT * FROM cte;
RETURN;
END;
Than create a view:
CREATE VIEW my_view
AS
SELECT m.*
FROM Providers p
CROSS APPLY my_function (p.ProviderId) m
After that you can SELECT from view whatever you need:
SELECT *
FROM my_view
WHERE ProviderId in (2,3,9)
OPTION (MAXRECURSION 0)
One way to do Table Valued Route
CREATE FUNCTION [dbo].[MVParam_tvf](#ParameterString nvarchar(4000), #Delimiter char(1)= ',')
RETURNS #VALUES TABLE (Param nvarchar(4000))AS
Figure out your code preference to spilt delimited string to table
END
CREATE FUNCTION dbo.MagicView_tvf
(
#ParameterString NVARCHAR(4000)
,#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN
(
with CTE as (
select Id, ProviderId, ConsumerId
from
T1 t
INNER JOIN MVParam_tvf (#ParameterString, #Delimiter) p
ON CAST(t.ProviderId AS VARCHAR(10)) = p.OutPutColumn
union all
select T1.Id, T1.ProviderId, T1.ConsumerId
from T1
join CTE on C.ProviderId = CTE.ConsumerId
)
select * from CTE
)
GO
SELECT * FROM dbo.MagicView_tvf ('2,3,9')
If you want to go the view route create the view without the where line on anchor part of cte and then when you call it write your where statement on that query.

"Invalid Column" when using column from table variable

I'm trying to declare a table variable and then join it to a table I created in the database. Every time I try to insert my "NAME" field into my table, I get the error 'Invalid Column Name "NAME"', even though the GNAME field works fine. What am I doing wrong, and how can I join me NAME column?
DECLARE #Names TABLE
(
ID INT,
NAME VARCHAR(100),
GNAME VARCHAR(100)
)
INSERT INTO #Names
(
ID,
NAME,
GNAME
)
SELECT
CName.ID,
Ref.NAME,
Ref.GNAME
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.ID = Ref.ID
IF ( OBJECT_ID('dbo.ReportTable', 'U') IS NOT NULL)
DROP TABLE dbo.ReportTable
CREATE TABLE [dbo].[ReportTable]
(
[ID_NUMBER] [INT],
[NAME] [VARCHAR](150)
[GNAME] [VARCHAR](150)
)
INSERT INTO [dbo].[ReportTable]
(
ID_NUMBER,
NAME,
GNAME
)
SELECT
C.ID_NUMBER,
N.NAME,
N.GNAME
FROM
#Names AS N
INNER JOIN
#CurrentPositions AS C
ON N.ID_NUMBER = C.ID_NUMBER
Try using a Temp table :
CREATE TABLE #Names
(
ID INT,
NAME VARCHAR(100),
GNAME VARCHAR(100)
)
INSERT INTO #Names
(
ID,
NAME,
GNAME
)
SELECT
CName.ID,
Ref.NAME,
Ref.GNAME
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.ID = Ref.ID
IF ( OBJECT_ID('dbo.ReportTable', 'U') IS NOT NULL)
DROP TABLE dbo.ReportTable
CREATE TABLE [dbo].[ReportTable]
(
[ID_NUMBER] [INT],
[NAME] [VARCHAR](150)
[GNAME] [VARCHAR](150)
)
INSERT INTO [dbo].[ReportTable]
(
ID_NUMBER,
NAME,
GNAME
)
SELECT
C.ID_NUMBER,
N.NAME,
N.GNAME
FROM
#Names AS N
INNER JOIN
#CurrentPositions AS C
ON N.ID_NUMBER = C.ID_NUMBER
I've assumed that you will also change the table variable #CurrentPositions to a temp table
Just remember to drop the tables after you use them.
It is quite possible that all you need to do is wrap your field names in square brackets, e.g.
INSERT INTO #Names
(
[ID],
[NAME],
[GNAME]
)
SELECT
CName.[ID],
Ref.[NAME],
Ref.[GNAME]
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.[ID] = Ref.[ID]
If that doesn't fix it, please post the schema of your #CurrentPositions and dbo.NameField tables.

SQL Query using distinct and max

I have a dataset like:
type seqID text
A 1 Text1a
A 2 Text2a
A 3 Text3a
B 1 Text1b
B 2 Text2b
How do I get the row back by type with the highest seqID grouped by type? So in the above example I would want the row that has A, 3, Text3a and B, 2, Text2b returned.
SELECT *
FROM tmp t1
WHERE NOT EXISTS
(SELECT 1 FROM tmp t2 WHERE t1.type = t2.type AND t2.seqID > t1.seqID)
It shouldn't exists any other row with the same type and higher seqID.
You kind of need an ID, but since "Text" seems unique for this example
CREATE TABLE #TMP
(type VARCHAR(3), seqID INT, [text] varchar(256))
insert #TMP values ('A' , 1 , 'Text1a')
insert #TMP values ('A' , 2 , 'Text2a')
insert #TMP values ('A' , 3 , 'Text3a')
insert #TMP values ('B' , 1 , 'Text1b')
insert #TMP values ('B' , 2 , 'Text2b')
SELECT * FROM #TMP T
where [text] IN
(SELECT TOP 1 [text] FROM #TMP t2 WHERE t.type = t2.type ORDER BY t2.seqID DESC)
SELECT tbl.*
FROM
( SELECT type, MAX(seqID)
FROM tbl
GROUP BY type) maxes
WHERE
tbl.type= maxes.type AND
tbl.seqID= maxes.seqID
SELECT t.* FROM
(
SELECT type, MAX(seqID) as maxId
FROM Table
GROUP BY type
) m
INNER JOIN Table t ON m.maxId = t.seqId
Using CTE
;WITH maxIds(maxId)
AS
(
SELECT type, MAX(seqID) as maxId
FROM Table
GROUP BY type
)
SELECT t.* FROM
Table t
INNER JOIN maxIds m ON m.maxId = t.seqID
If you are on SQL Server 2005+, you could use a ranking function (more specifically, ROW_NUMBER()):
SELECT
type,
seqID,
text
FROM (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY type ORDER BY seqID DESC)
FROM atable
) s
WHERE rnk = 1
create table #tlb1(
[type] VARCHAR(3), seqID INT, [text] varchar(max)
)
declare #type varchar(3), #text varchar(max);
declare #seqID int;
declare seq_cursor cursor for
select [type], max(seqID) from tbl group by [type]
open seq_cursor
fetch next from seq_cursor into #type,#seqID
while(##fetch_status=0)
begin
set #text= (select [text] from tbl where [type]=#type and seqID=#seqid);
insert into #tlb1 values (#type, #seqID,#text);
fetch next from seq_cursor into #type,#seqID
end
select * from #tlb1
close seq_cursor
deallocate seq_cursor
truncate table #tlb1
Try:
SELECT type, max(seqID),text
FROM 'db'
GROUP BY type
As easy as that.
EDITED solution. Consider this a psuedo-code (since I am not familiar with SQL server syntax):
SELECT a.type, a.seqID, a.text FROM table a
JOIN
(SELECT type, max(seqID) seqID FROM table GROUP BY type) b
ON a.seqID = b.seqID AND a.type=b.type