Column names in result and rotate part of table - sql

The following a table structure:
'----ID-----'----NAME----'----FIELD1----'----FIELD2----'
' 1 ' val ' 123 ' 321 '
' 2 ' val2 ' 234 ' 212 '
Need to get the following result:
'----ID-----'----NAME----'----FIELDS----'----VALUES----'
' 1 ' val ' FIELD1 ' 123 '
' 1 ' val ' FIELD2 ' 321 '
' 2 ' val2 ' FIELD1 ' 234 '
' 2 ' val2 ' FIELD2 ' 212 '
How write this query? I can get column names from INFORMATION_SCHEMA.COLUMNS. But how to join table with INFORMATION_SCHEMA.COLUMNS? Also how can rotating a part of table?
As living example. Following is table:
On screenshot only several fields but in table there are a lot of fields. I wrote the following query:
Select p.GUID, p.myvalues, p.Fields
from myTable gz
unpivot( [myvalues] for Fields in ([area], [davlplastmax])) p
But this query doesn't return null values.
Also I want get columns from INFORMATION_SCHEMA.COLUMNS and past them in ([area], [davlplastmax]).
For example:
unpivot( [values] for Fields in (
SELECT [MyDb].INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME
FROM [MyDb].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'MyTable'
)

Unpivot?
select u.id, u.name, u.fields, u.values
from MyTable t
unpivot
(
values
for fields in (Field1, Field2)
) u;

You can use unpivot as below:
Select * from #data
unpivot( [values] for Fields in ([Field1],[Field2])) p
Output as below:
+----+------+--------+--------+
| Id | Name | values | Fields |
+----+------+--------+--------+
| 1 | val | 123 | Field1 |
| 1 | val | 321 | Field2 |
| 2 | val2 | 234 | Field1 |
| 2 | val2 | 212 | Field2 |
+----+------+--------+--------+
You can use dynamic query as below for getting columns from Information_Schemas
Declare #cols1 varchar(max)
Declare #query nvarchar(max)
Select #cols1 = stuff((select ','+QuoteName(Column_Name) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'TestData'
and COLUMN_NAME not in ('Id','Name') for xml path('')),1,1,'')
Select #query = ' Select * from
(Select * from #data )a
unpivot( [values] for Fields in (' + #cols1+ ')) p '
Exec sp_executeSql #query

Related

Retrieving multiple rows dynamically using Pivot in SQL

I wish to add multiple rows for a particular pivot table.
Table name : MasterTable
FieldName | FieldValue
------------------------
Field1 | F1value1
Field2 | F2value1
Field3 | F3value1
Field1 | F1value2
Field2 | F2value2
Field3 | F3value2
Expected result:
Field1 | Field2 | Field3
---------------------------------
F1value1 | F2value1 | F3value1
F1value2 | F2value2 | F3value2
I tried this code but result me with only one row.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(FieldName) from MasterTable FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT ' + #cols + ' from (select FieldName, FieldValue from MasterTable ) x
pivot
(
max(FieldValue)
for FieldName in (' + #cols + ')
) p '
execute(#query)
Output:
Field1 | Field2 | Field3
---------------------------------
F1value1 | F2value1 | F3value1
Could someone please help me to have multiple rows using pivote table.
For the subquery, use:
(select FieldName, FieldValue,
row_number() over (partition by FieldName order by FieldName) as seqnum
from MasterTable
)
pivot will take this into account in the pivoting.
Note: This will guarantee the number of rows, but the ordering of each column is arbitrary. You may want to replace the order by with a reasonable column for ordering.

Column name in separate table

I need to analyze application data, and it stores data in separate table from definition (column names). Something like this:
Data table1:
id | 1234 | 1235 | 1236
---|------|------|-----
1 | val1 | val2 | val3
Model:
tableID | colID | Name
--------|-------|-----
table1 | 1234 | Name
table1 | 1235 | DOB
table1 | 1236 | Sex
table2 | 1237 | Manager
etc...
I want to get this data like this:
Data:
id | Name | DOB | Sex
---|------|------|-----
1 | val1 | val2 | val3
Is it possible? Additional problem is that in each data table there might be different number of columns.
UPD.
Problem solved by #Prdp
Though, i've changed query a little bit:
DECLARE #col_list VARCHAR(max)
SET #col_list = Stuff((SELECT ',' + Quotename(af.ColID) + ' as ' + Quotename(af.Name)
FROM [Model].dbo.Fields af
WHERE af.[App.ID] = 123
FOR xml path ('')), 1, 1, '')
EXEC('select '+#col_list+' from [Data].dbo.[123]')
As mentioned in comments better to handle this in application layer. If in case you want a sql solution then you need dynamic query
DECLARE #col_list VARCHAR(8000)
SET #col_list = Stuff((SELECT ',' + Quotename(colID) + ' as ' + Quotename(NAME)
FROM Model
WHERE EXISTS (SELECT 1
FROM information_schema.columns
WHERE table_name = 'Data'
AND Cast(colID AS VARCHAR(50)) = column_name)
FOR xml path ('')), 1, 1, '')
EXEC('select '+#col_list+' from data')

how to write a query to separate each column by comma without specifying each column name

How to write a query so that each column of table1 separated by comma
Without including each column name
+------+-----+-----------+-------------+
| eno |dno | ename | job_type |
+------+-----+-----------+-------------+
| 101 | 1 | sam | manager |
| 102 | 2 | ash | teacher |
| 103 | 3 | rohan | clerk |
| 104 | 4 | sohan | peon |
| 105 | 5 | mohan | guar |
+------+-----+------------+------------+
I want to output like this
101,1,sam,manager
102,2,ash,teacher
And rest are same
With the help of a CROSS APPLY (or two), a little XML and STUFF()
A word of caution: This approach will EXCLUDE NULL values
Declare #YourTable table (eno int,dno int, ename varchar(25),job_type varchar(25))
Insert Into #YourTable values
(101,1,'sam' , 'manager'),
(102,2,'ash' , 'teacher'),
(103,3,'rohan', 'clerk' ),
(104,4,'sohan', 'peon' ),
(105,5,'mohan', 'guar' )
Select C.*
From #YourTable A
Cross Apply (Select XMLData=cast((Select A.* for XML Raw) as xml)) B
Cross Apply (
Select String=Stuff((Select ',' +Value
From (
Select Value = attr.value('.','varchar(max)')
From XMLData.nodes('/row') as A(r)
Cross Apply A.r.nodes('./#*') AS B(attr)
) X
For XML Path ('')),1,1,'')
) C
Returns
String
101,1,sam,manager
102,2,ash,teacher
103,3,rohan,clerk
104,4,sohan,peon
105,5,mohan,guar
You can also do it with a dynamic sql query.
Query
declare #sql as varchar(max);
select #sql = 'select case when right(t.csv, 1) = ' + char(39) + ',' + char(39)
+ ' then left(t.csv, len(t.csv) - 1) else t.csv end as csv from(select '
+ stuff((select '+ case when [' + column_name + '] is null then '
+ char(39) + char(39) +
' else cast([' + column_name + '] as varchar(max)) + '
+ char(39) + ',' + char(39) + ' end'
from information_schema.columns
where table_name = 'dds_emp'
order by ordinal_position asc
for xml path('')
), 1, 1, '');
select #sql += ' as csv from dds_emp)t;';
exec(#sql);

Convert Decimal to String on Pivot

example Code
Declare
#table1 VARCHAR(MAX)
Set #table1 = 'Select * from #tempTbl'
Declare
#List VARCHAR(MAX),
#Pivot VARCHAR(MAX)
Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB'
Set #Pivot = '
SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, *
FROM (
Select Distinct
c.UserId,
d.Name,
b.TrxCd
SUM(b.Amount) As Amount
From tbl_InvH a
Inner Join tbl_InvD b on a.subCd = b.subCd and a.InvNo = b.InvNo
Left Join tbl_User c On a.UserId = c.UserId
Left Join tbl_Personnel d on c.PersonnelId = d.PersonnelId
Group By c.UserId, d.Name, b.TrxCd
) as s
PIVOT
(
SUM(Amount)
FOR TrxCd IN (' + #List + ')
)AS pvt'
Declare #Result nVarchar(MAX)
Set #Result = #table1 + '
Union All
' + #Pivot
Exec sp_executesql #Result
I want to Convert Field Amount from decimal to String, because after this I want to UNION with another tables, but field amount and field from another table is different type.
I have tried CAST(SUM(Amount) as Varchar) But Error :
'CAST' is not a recognized aggregate function.
I can't Convert on Main Select because Field of TrxCd is Dynamic
Result Of Pivot
RowIndex | UserId | Name | IT01 | IT02 | IT03 | IT04
--------------------------------------------------------------------------------
1 | John | John Ivy | 2,000 | 2,000 | 1,000 | 5,000
2 | Merry | Merry Ish | 1,000 | 1,000 | 1,000 | 6,000
other Table
RowIndex | UserId | Name | Transac1 | Transac2 | Transac3 | Transac4
-------------------------------------------------------------------------------------------------
1 | John | John Ivy | Trx Bank A | Trx Bank B | Trx Bank C | Trx Bank D
What should I do to Convert Field Amount from Pivot.
Because of the dynamic nature, you could take the same #List expression Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB' and create a second for the dynamic casting in the main select;
Select #List2 = ISNULL(#List2 + ',', '') + 'cast(' + TrxCd + 'as varchar)' From TransacMaster Where Module = 'CB'
Then use this and additional columns required to replace the asterix in the main select;
'SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, UserId, Name,' + #List2 +'....'

How to merge SQL rows with null values

I have many rows for the same data but each row has a different columns populated. I want to join all these rows into a single row. I have tried group by, but the dataset has 1000 columns. Any suggestions?
SELECT TOP 100 *
FROM [Hilltopsamplerfix].[dbo].[tempHilltopWaterQualityExtractPivot]
WHERE [SiteName] = 'site' AND [RunDate] = 'xxx'
Example of the data
I can't paste an image because my reputation is under 10
+------------------------------+
| Site column1 column2 column3 |
+------------------------------+
| SITE1 NULL NULL 76 |
| SITE1 NULL 23 NULL |
| SITE1 NULL NULL NULL |
+------------------------------+
Desired output:
+------------------------------+
| Site column1 column2 column3 |
+------------------------------+
| SITE1 NULL 23 76 |
+------------------------------+
You need to use group by:
select site, max(column1) as column1, max(column2) as column2, . . .
from [Hilltopsamplerfix].[dbo].[tempHilltopWaterQualityExtractPivot]
group by site;
You can get the columns in the table from information_schema.columns and construct the logic in the SQL or Excel. For example
select ' max(' + column_name + ') as ' + column_name + ', '
from information_schema.columns
where table_name = 'tempHilltopWaterQualityExtractPivot' and
column_name <> 'site';
Then copy the results into the query window.
Try this below SQL, Based on Gordon
Declare #Cols Varchar(Max)
select #Cols= coalesce(#Cols+',', '')+ ' max(' + column_name + ') as ' + column_name
from information_schema.columns
where table_name = 'tempHilltopWaterQualityExtractPivot' and Column_Name <> 'site'
Declare #Query Varchar(max)
SET #Query='Select Site, '+ #Cols+' From tempHilltopWaterQualityExtractPivot Group by Site'
EXEC(#Query)