Create table from query - sql

I managed to apply the PIVOT statement you suggested to transpose the values ​​of the records of a table as columns automatically:
DECLARE #PivotColumnas VARCHAR(MAX)
SELECT #PivotColumnas = COALESCE (#PivotColumnas + ',[' + IB_PDSBATCHATTRIBIDBI + ']', '[' + IB_PDSBATCHATTRIBIDBI + ']') FROM PDSBATCHATTRIB
DECLARE #PivotTablaSQL NVARCHAR(MAX)
SET #PivotTablaSQL = N' SELECT *
FROM (SELECT INVENTBATCHID, ITEMID, PDSBATCHATTRIB.IB_PDSBATCHATTRIBIDBI, PDSBATCHATTRIBVALUE FROM PDSBATCHATTRIBUTES
LEFT JOIN PDSBATCHATTRIB ON PDSBATCHATTRIBUTES.IB_PDSBATCHATTRIBIDBI = PDSBATCHATTRIB.IB_PDSBATCHATTRIBIDBI) AS TablaOrigen
PIVOT
(MIN(PDSBATCHATTRIBVALUE)
FOR IB_PDSBATCHATTRIBIDBI IN ('+ #PivotColumnas + ')) AS PivotTable'
EXECUTE (#PivotTablaSQL)
What I need is how to save the result as a query or create a table from this query. If I try to save the result as a query, I get the following error:
Incorrect syntax near the keyword 'DECLARE'.
Thanks!

Because it is a dynamic sql, and you don`t know the exact columns, you can use an SELECT ... INTO #TempPivot. It is creating a temporary table what you can use later, or try to build up a dynamic solution which can select the temp table's structure and create a table, however it seems a bit overkill.

I found the solution, is very simple in fact!
I only have to add the command INTO NewTable in the SELECT sentence oof the pivot table, just like that:
SET #PivotTablaSQL = N' SELECT * **INTO NewTable**
FROM (SELECT INVENTBATCHID, ITEMID, PDSBATCHATTRIB.IB_PDSBATCHATTRIBIDBI, PDSBATCHATTRIBVALUE FROM PDSBATCHATTRIBUTES
LEFT JOIN PDSBATCHATTRIB ON PDSBATCHATTRIBUTES.IB_PDSBATCHATTRIBIDBI = PDSBATCHATTRIB.IB_PDSBATCHATTRIBIDBI) AS TablaOrigen
PIVOT
(MIN(PDSBATCHATTRIBVALUE)
FOR IB_PDSBATCHATTRIBIDBI IN ('+ #PivotColumnas + ')) AS PivotTable'
This create a new table in the SQL database with the pivot table results.
Thanks all!

Related

Using the result of a CTE to query from table without cursor

I need to query from a table which is a result of a CTE query e.g.
;WITH CTE
AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT * FROM CTE
This will return me the names of the tables which I need to query data from.
Can I use the CTE to query from the respective tables e.g. SELECT * FROM dbo.[1006UN]? I know I could use a temp table to store these values and use a cursor to iterate with dynamic sql but I do not want to use a cursor, if at all possible.
I have tried something as simple as:
SELECT * FROM dbo.[CTE]
Which gives me the error:
Invalid object name 'dbo.CTE'.
And have went further to attempt to use dynamic SQL with the CTE:
DECLARE #query1 VARCHAR(MAX)
SELECT #query1 = N';WITH CTE
AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT * FROM dbo.["' + CTE + '"] '
EXECUTE(#query1)
Which gives me the error:
Invalid column name 'CTE'.
So firstly, is it possible to achieve this? And if not, are there any alternatives which can achieve this (avoiding cursors)?
Can be done. It's irrelevant if you use CTE or not. Once you have your tables names you can create and concatenate dynamic SELECT statements.
DECLARE #query NVARCHAR(MAX) = '';
WITH CTE AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT #query = #query + 'SELECT * FROM ' + QUOTENAME(TableName) + '; '
FROM CTE;
PRINT #query; --run print first to check
EXEC (#query);

Dynamic Pivot in MS SQL Server

I am trying to do a dynamic pivot on the last two columns that i take from one table and am joining onto the contents of another table. I need the Name values to pivot to the header fields and the Value values to fill in correspondingly underneath. This is my current query:
USE Innovate
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(NAME)
FROM (SELECT DISTINCT NAME FROM Innovate.dbo.Table1 WHERE Name IS NOT NULL) AS ATTRIBUTE_NAME
WHERE Name LIKE 'Suture_-_2nd_Needle_Code'
OR Name LIKE 'Suture_-_Absorbable'
OR Name LIKE 'Suture_-_Antibacterial'
OR Name LIKE 'Suture_-_Armed'
OR Name LIKE 'Suture_-_Barbed'
OR Name LIKE 'Suture_-_Brand_Name'
OR Name LIKE 'Suture_-_C/R_2nd_Needle_Code'
OR Name LIKE 'Suture_-_C/R_Brand_Name'
OR Name LIKE 'Suture_-_C/R_length'
OR Name LIKE 'Suture_-_C/R_Needle_Code'
OR Name LIKE 'Suture_-_Coating'
OR Name LIKE 'Suture_-_Dyed'
OR Name LIKE 'Suture_-_Filament'
OR Name LIKE 'Suture_-_length_inches'
OR Name LIKE 'Suture_-_Looped'
OR Name LIKE 'Suture_-_Material'
OR Name LIKE 'Suture_-_Needle_Code'
OR Name LIKE 'Suture_-_Needle_Shape'
OR Name LIKE 'Suture_-_Needle_Style'
OR Name LIKE 'Suture_-_Noun'
OR Name LIKE 'Suture_-_pleget'
OR Name LIKE 'Suture_-_Popoff'
OR Name LIKE 'Suture_-_Suture_count'
OR Name LIKE 'Suture_-_Suture_size'
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT Table1.Primary_Key, Company_Name, Part_Number, Product_Desc, Innovate_Description, ' + #ColumnName + '
FROM Table1 AS P
LEFT JOIN Table2 AS A ON P.Primary_Key = A.Primary_Key
PIVOT(MAX(A.VALUE)
FOR A.NAME IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXECUTE sp_executesql #DynamicPivotQuery
;
And this is the Result for the Query that I keep getting: Msg 8156,
Level 16, State 1, Line 5 The column 'Primary_Key' was specified
multiple times for 'PVTTable'. Msg 4104, Level 16, State 1, Line 1 The
multi-part identifier "Table1.Primary_Key" could not be bound.
Can anyone help me pivot these columns without the error message? I only specified the Primary_Key in the code once so I do not know how I specified it multiple times and how it is unbound.
Try with the below script..
SET #DynamicPivotQuery =
N'SELECT P.Primary_Key, Company_Name, Part_Number, Product_Desc, Innovate_Description, ' + #ColumnName + '
FROM Table1 AS P
LEFT JOIN Table2 AS A ON P.Primary_Key = A.Primary_Key
PIVOT(MAX(A.VALUE)
FOR A.NAME IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXECUTE sp_executesql #DynamicPivotQuery
you have a couple of things going on with your PIVOT statement that are problematic. First you are attempting to reference table aliases for Table1 and Table2 but those aliases are not available in the final select of a PIVOT the Pivot command is kind of like an outer select and the only table alias that is then available is the pivot alias.
Next pivot's documenation states "You can use the PIVOT and UNPIVOT relational operators to change a table-valued expression into another table" (https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx). Basically that means that you need a single table expression of only the uniquely named columns you want to be involved pivot being passed to the PIVOT command. The later part is likely the issue as Table1 and Table2 probably both have a column Primary_Key so pivot doesn't understand the reference.
To fix you can either move your Table1 & 2. join to an inner select and alias the table or build a cte and use the cte in your command. Here is the former way:
SET #DynamicPivotQuery =
N'SELECT * FROM
(
SELECT Table1.Primary_Key, Company_Name, Part_Number, Product_Desc, Innovate_Description, ' + #ColumnName + '
FROM Table1 AS P
LEFT JOIN Table2 AS A ON P.Primary_Key = A.Primary_Key
) t
PIVOT(MAX(A.VALUE)
FOR NAME IN (' + #ColumnName + ')) AS PVTTable'
Those Name values get hardcoded to calculate that #ColumnName variable.
If the values are hardcoded anyway, then you might as well run the pivot with a join without building a SQL statement to execute.
SELECT A.Company_Name, A.Part_Number, A.Product_Desc, A.Innovate_Description, P.*
FROM (select Primary_Key, Name, Value from Innovate.dbo.Table1) T1
PIVOT(MAX(VALUE) FOR NAME IN (
[Suture_-_2nd_Needle_Code],
[Suture_-_Absorbable],
[Suture_-_Antibacterial],
[Suture_-_Armed],
[Suture_-_Barbed],
[Suture_-_Brand_Name],
[Suture_-_C/R_2nd_Needle_Code],
[Suture_-_C/R_Brand_Name],
[Suture_-_C/R_length],
[Suture_-_C/R_Needle_Code],
[Suture_-_Coating],
[Suture_-_Dyed],
[Suture_-_Filament],
[Suture_-_length_inches],
[Suture_-_Looped],
[Suture_-_Material],
[Suture_-_Needle_Code],
[Suture_-_Needle_Shape],
[Suture_-_Needle_Style],
[Suture_-_Noun],
[Suture_-_pleget],
[Suture_-_Popoff],
[Suture_-_Suture_count],
[Suture_-_Suture_size]
)
) P
LEFT JOIN Innovate.dbo.Table2 AS A ON (A.Primary_Key = P.Primary_Key);
Fair enough, this has a disadvantage that if that [Primary_Key] needs to be the first column, that the P.* should be replaced by those literal column values. Or use the EXEC approach after all.
Anyway, to build name list for that #ColumnName variable, it can be done without all the OR's :
DECLARE #ColumnName NVARCHAR(MAX);
--Get distinct values of the PIVOT Column
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(NAME)
FROM Innovate.dbo.Table1
WHERE Name Like 'Suture_-_%'
AND SUBSTRING(Name,10,30) IN (
'2nd_Needle_Code',
'Absorbable',
'Antibacterial',
'Armed',
'Barbed',
'Brand_Name',
'C/R_2nd_Needle_Code',
'C/R_Brand_Name',
'C/R_length',
'C/R_Needle_Code',
'Coating',
'Dyed',
'Filament',
'length_inches',
'Looped',
'Material',
'Needle_Code',
'Needle_Shape',
'Needle_Style',
'Noun',
'pleget',
'Popoff',
'Suture_count',
'Suture_size')
GROUP BY Name;

Assistance with a SQL query parsing JSON

I have a database table called QueueItems that contains the following fields:
SpecificData contains JSON data so we have used the well known parseJSON SQL function that is about on the internet.
So an example of the JSON is below:
{"DynamicProperties":{"IdentificationIndex":"CK","PaymentMethod":"C","Variants1":"010 ZERO BAL,716 ZERO BAL,717 ZERO BAL","Variants2":"CHECK_010,CHECK_716,CHECK_717","CustomerCode":"NO","FreeSelectionField":"NO","FreeSelectionValue":"NO","Variants1Line":"RFFOAVIS","Variants2Line":"ZRFFOUS_C","VendorFrom":"1","VendorTo":"999999999","DueDateCheck":"Yes","PaymentMethodSel":"Yes","PaymentMethodSelOnFail":"No","LineItemsOfPayDocs":"Yes","StartImmediately":"Yes","CreatePaymentMedium":"No","ExportFormat":"HTML Format","ExcludeValues":"Yes"}}
When I run the SQL function parseJSON it returns me the data in this format:
Now, the query I am trying to write is:
SELECT QueueItemID, QueueItemStatus, StartProcessing, EndProcessing, [THEN append each column from parseJSON but this needs to be transposed first]
So far I have managed to transpose the JSON into columns with a single row using:
DECLARE
#Cols AS VARCHAR(MAX) = ''
,#Query AS NVARCHAR(MAX) = ''
,#ParamDef AS NVARCHAR(MAX)
,#Json AS VARCHAR(MAX) = '{"DynamicProperties":{"IdentificationIndex":"CK","PaymentMethod":"C","Variants1":"010 ZERO BAL,716 ZERO BAL,717 ZERO BAL","Variants2":"CHECK_010,CHECK_716,CHECK_717","CustomerCode":"NO","FreeSelectionField":"NO","FreeSelectionValue":"NO","Variants1Line":"RFFOAVIS","Variants2Line":"ZRFFOUS_C","VendorFrom":"1","VendorTo":"999999999","DueDateCheck":"Yes","PaymentMethodSel":"Yes","PaymentMethodSelOnFail":"No","LineItemsOfPayDocs":"Yes","StartImmediately":"Yes","CreatePaymentMedium":"No","ExportFormat":"HTML Format","ExcludeValues":"Yes"}}'
SELECT
#Cols += ',' + Name
FROM
parseJson(#Json)
WHERE
Name NOT IN ('DynamicProperties', '-')
SET #Cols = SUBSTRING(#Cols,2,LEN(#Cols))
SET #Query = N'SELECT *
FROM
(
SELECT [StringValue], [Name]
FROM parseJson(''' + #Json + ''')
) [d]
PIVOT
(
MAX([StringValue])
FOR [Name] IN (' + #Cols + ')
) [piv]'
EXECUTE (#Query)
As you can see the JSON may contain ANY data, so I am dynamically inserting the column names into the PIVOT statement FOR IN.
Now to Join this data as additional columns onto my main query SELECT QueueItemId.. FROM QueueItems I was originally going to put this code in a UDF and call it as part of my main query / stored procedure but I have two issues:
1) The sp_executesql or EXEC statement - not allowed in a UDF
2) To return a table from a UDF I need to define the fields... The fields are dynamic... I could get this working by passing back XML to my stored procedure but I still have issue number 1.
So the question is:
1) Is there any better way or writing this then using a UDF?
2) Is there any other way or transposing the output from parseJSON?
3) Is there any other way of using the PIVOT but not having to specify the columns?
Any help would be much appreciated.
EDIT IN RESPONSE TO M ALI
I know the syntax is wrong and it doesn't work but the query would look something like this:
DECLARE #Cols AS VARCHAR(MAX) = ''
,#Query AS NVARCHAR(MAX) = ''
SELECT
QI.QueueItemID,
QI.QueueItemStatus,
QI.StartProcessing,
QI.EndProcessing,
SD.*
FROM QueueItems AS QI
LEFT JOIN
(
SELECT
#Cols += ',' + Name
FROM
parseJson(QI.SpecificData)
WHERE
Name NOT IN ('DynamicProperties', '-')
SET #Cols = SUBSTRING(#Cols,2,LEN(#Cols))
SET #Query = N'SELECT *
FROM
(
SELECT [StringValue], [Name]
FROM parseJson(''' + QI.SpecificData + ''')
) [d]
PIVOT
(
MAX([StringValue])
FOR [Name] IN (' + #Cols + ')
) [piv]'
EXECUTE (#Query)
) AS SD
And the results would be the columns from QueueItems, joined on the left by columns from the parsed JSON string.
QueueItemID, StartProcessing, EndProcessing, IndentificationIndex, PaymentMethod etc...

Concatenate rows into a single text string

I have seen similar questions but feel this is not a duplicate question. I would like to concatenate rows into single string with joins. I am confused on how to proceed. Syntax below
I am getting an error "There is already an object named '#TEMPTABLE' in the database." also I am not sure if my sytax to the 2nd select statement is correct, help?
SELECT DISTINCT DisplayName, addrSt, addrCntyName,
RIGHT('00' + CONVERT(varchar, addrStFips), 2) + RIGHT('000' + convert(varchar, addrCntyFips), 3) AS addrFips
INTO #TEMPTABLE
FROM PPP
INNER JOIN poa ON PPP.OAJ = poa.OAJ
INNER JOIN dcPfp ON PfpPayor.KEYF = dbo.dcPfp.KEYJ
INNER JOIN ProvOff ON ProvOffAfl.OJK = ProvOff.OJK
SELECT DISTINCT
addrFips,
STUFF
(
(
SELECT ',' + DisplayName
FROM #TEMPTABLE M
WHERE M.addrFips = B.addrFips
ORDER BY DisplayName
FOR XML PATH('')
),1,1,''
) AS DISPLAYNAMES
FROM #TEMPTABLE B
DROP TABLE #TEMPTABLE
The error message There is already an object named '#TEMPTABLE' in the database. means that you've created a temporary table with this name in a previous run. To solve this, you need to DROP this table or use another name.
To drop, use the following code before your query:
IF OBJECT_ID('tempdb..#TEMPTABLE') IS NOT NULL
DROP TABLE #TEMPTABLE
What worked in my situation was IF OBJECT_ID('tempdb.#TEMPTABLE') IS NOT NULL DROP TABLE #Results
GO
Thank you all!
You can use undocumented string concatenation feature.
DECLARE #big_string varchar(max) = '';
SELECT #big_string += x.s + ','
FROM (VALUES ('string1'), ('string2'), ('string3')) AS x(s);
SELECT #big_string;
-- OUTPUT:
-- string1,string2,string3,
It's that easy. As for order guarantees, read this article.

TSQL: How to add automatically select columns

I have a problem and can't solve it. Furthermore I can't find an answer anywhere in the internet.
Simplified I have a big table with coloumns, where values to products with an ID are stored by year:
year
id
value
In my stored procedure the attributes for getting information are:
#year
#id
If you want to get information about more than one product, you can use a comma-seperated list of product-ids like ('654654,543543,987987').
My TSQL should be like this:
select year,
sum(case when id = #id[1] then value),
sum(case when id = #id[2] then value),
[...]
from table myTable
where year = #year
group by year
order by year
What I want to do is iterate throught the comma-seperated ids and for each id, I want to add a new select attribut like this (sum(case when id = #id[x] then value).
Can you help me with this problems? Any suggestions to solve it?!
Thanks for your help!
PIVOT operation could simplify the query.
But, anyway, it seems that the only way to construct such a query is to use dynamic SQL.
DECLARE
#Ids NVARCHAR(MAX),
#stmt NVARCHAR(MAX)
SET #Ids = '1,2'
-- Transform Ids into the format PIVOT understands - with square brackets.
-- Primitive way, to not overcomplicate sample.
SET #Ids = '[' + REPLACE(#Ids, ',', '], [') + ']'
PRINT #Ids -- [1], [2]
SET #Stmt = '
SELECT *
FROM Products as p
PIVOT
(
SUM(p.Value)
FOR p.Id IN (' + #Ids + ')
) AS t
ORDER BY Year'
EXEC sp_executesql #Stmt
If you need more accurate way of splitting a comma separated list into an array (table), please see this article for details.
This example is available on SQL Fiddle
As you are using stored procedure, you can use sp_executesql to executed dynimically build SQL statement.
So, you have to iterate over the CSV like this:
DECLARE #List NVARCHAR(MAX) = N'1001,dada,1002,1003'
DECLARE #ProductsID TABLE ( [ID] BIGINT )
DECLARE #XML xml = N'<r><![CDATA[' + REPLACE(#List, ',', ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO #ProductsID ([ID])
SELECT DISTINCT CAST(Tbl.Col.value('.', 'float') AS bigint)
FROM #xml.nodes('//r') Tbl(Col)
WHERE ISNUMERIC(Tbl.Col.value('.', 'varchar(max)')) = 1
SELECT [ID] FROM #ProductsID
Then, having a table with the ID to dynamically build you SQL statement and execute it.