String functions to generate dynamic query in SQL Server 2008 - sql

Select * from MyTable gives the following result
AttributeID AttributeName
------------------------------------ ------------------------
6B93119B-263B-4FED-AA89-198D26A3A3C4 DOB
E27DBA94-F387-460A-BC02-84878692BDF6 Sex
ABF3B85C-0DEA-44FE-857A-AC63520F7294 History
Now I want to generate a dynamic query in the following format (to be used with PIVOT)
SELECT
[6B93119B-263B-4FED-AA89-198D26A3A3C4] DOB,
[E27DBA94-F387-460A-BC02-84878692BDF6] Sex,
[ABF3B85C-0DEA-44FE-857A-AC63520F7294] History
How can I do it in SQL Server 2008?

DECLARE #query VARCHAR(MAX)
SET #query = 'SELECT '
SELECT #query = #query + '[' + CONVERT(NVARCHAR(50),AttributeID) + '] ' + AttributeName + ','
FROM MyTable
PRINT #query

The following produces the desired result for me:
DECLARE #Query VARCHAR(MAX);
SET #Query = 'SELECT ';
WITH Data AS (
SELECT '6B93119B-263B-4FED-AA89-198D26A3A3C4' AS AttributeID, 'DOB' AS AttributeName
UNION ALL
SELECT 'E27DBA94-F387-460A-BC02-84878692BDF6', 'Sex'
UNION ALL
SELECT 'ABF3B85C-0DEA-44FE-857A-AC63520F7294', 'History'
)
SELECT #Query = #Query + '''' + AttributeID + ''' ' + AttributeName + ', '
FROM Data
SET #Query = SUBSTRING(#Query, 1, LEN(#Query) - 1);
SELECT #Query
Edit: Just to be clear, the section of SQL in the above sample beginning "WITH Data AS (" and ending at the close bracket (")") is just there as sample data. You can omit it entirely, so the sample becomes:
DECLARE #Query VARCHAR(MAX);
SET #Query = 'SELECT ';
SELECT #Query = #Query + '''' + AttributeID + ''' ' + AttributeName + ', '
FROM MyTable
SET #Query = SUBSTRING(#Query, 1, LEN(#Query) - 1);
SELECT #Query

Related

How do a pivot on sql server on one column but renamed dynamics column

I've a table of prices With Reference, Price Category (Ex professional/Customer...) , the weight and the price
Each article have X lines for same Reference, Price Category depend of weight
I Want a return with Reference, Price Category, Price1,Price2...
I try to adapt codes I've found but I've a problem to linked weight and named columns PRIX1,PRIX2...
declare #MAxcols as int
DECLARE #cols AS NVARCHAR(MAX)='';
/*max of differents price=max columns dynamic to add*/
set #Maxcols = (select max(NBLignes) from (select count(*) as NBLignes
FROM [Z_TARIFS_VENTE] as Results
GROUP BY AR_REF,Cat_Prx) as tmp)
/*Build all dynamic columns */
DECLARE #cnt INT = 0;
WHILE #cnt < #Maxcols
BEGIN
SET #cols = #cols + 'PRIX' + cast(#cnt+1 as nvarchar(3)) + ','
SET #cnt = #cnt + 1;
END
SET #cols=LEFT(#cols, LEN(#cols) - 1)/*remove last , = 'PRIX1,PRIX2,PRIX3...PRIXX'*/
DECLARE #query AS NVARCHAR(MAX);
SELECT #query =
'SELECT
[AR_Ref],
[Cat_Prx],
' + #cols + '
FROM (
Select
[AR_Ref],
[Cat_Prx],
[weight] ,
[PRIX]
From
[Z_TARIFS_VENTE]
) t
PIVOT
(
Sum(PRIX)
FOR weight IN( ' + #cols + ' )' +/* Here my problem*/
' ) AS p; ';
Execute(#query);
I don't want have each weight in separate column but only classify on Prix1, prix2...
Finally... Force to try
I create a view on my table With row number based on my group by
ROW_NUMBER() OVER (PARTITION BY [AR_Ref], [Cat_Prx]...)
AND In a stored procedure
declare #MAxcols as int
set #Maxcols = (select max(NBLignes) from (select count(*) as NBLignes
FROM [Z_TARIFS_VENTE] as Results
GROUP BY AR_REF,EG_Enumere,TQ_RefCF) as tmp)
DECLARE #query AS NVARCHAR(MAX);
SET #query ='SELECT [AR_Ref], [EG_Enumere],[TQ_RefCF]'
DECLARE #cnt INT = 1;
WHILE #cnt < #Maxcols + 1
BEGIN
SET #query = #query + ',CASE WHEN IdxRow=' + CAST(#cnt as nvarchar(3)) + ' THEN PRIX ELSE NULL END AS PRIX' + CAST(#cnt as nvarchar(3))
SET #cnt = #cnt + 1;
END
SET #query = #query + ' FROM Z_TARIFS_VENTE_ROWNUM'
EXECUTE sp_executesql #query
Now I just need to group by and on each added column put Max(Prix1) as prix1 ,...always using a variable string

Create a table with PIVOT

I have a query that rotates a stock prices table, but it uses a temp table.
I would like to know how to store this rotated table in a table.
I have struggled to use this query with 'create table' because there is some variables declarations.
Here is the code:
IF OBJECT_ID('TEMPDB..#TEMP','U') IS NOT NULL DROP TABLE #TEMP;
DECLARE #COL NVARCHAR(MAX);
DECLARE #SQL NVARCHAR(MAX);
DECLARE #HEADER NVARCHAR(MAX);
DECLARE #FIX NVARCHAR(MAX);
DECLARE #VAR NVARCHAR(MAX);
DECLARE #ORDER NVARCHAR(MAX);
WITH
#TEMP AS(
select Cast(MarketDate as Date) as date_, oo.seccode, ConstFlag
FROM
(select distinct seccode, InfoCode, MarketDate, Constflag
from ds_russell1000_prices_adj_r) oo
SELECT * INTO #TEMP
FROM #TEMP
SET #FIX = 'Date_';
SET #VAR = 'Constflag'
SET #HEADER = 'seccode';
SELECT #COL = COALESCE(#COL + ',','') + QUOTENAME(seccode) FROM #TEMP F
GROUP BY QUOTENAME(seccode)
ORDER BY QUOTENAME(seccode)
SET #ORDER = 'Date_'
SET #SQL = 'SELECT ' + #FIX + ',' + #COL + ' FROM (SELECT ' + #FIX + ',' +
VAR + ', ' + #HEADER + ' FROM #TEMP) P
PIVOT (sum(' + #VAR + ') FOR ' + #HEADER + ' in (' + #COL + ')) PVT
ORDER BY ' + #ORDER + ''
EXEC sp_executesql #SQL;
IF OBJECT_ID('ds_russell1000_positions_ROTATED') IS NOT NULL DROP TABLE
ds_russell1000_positions_ROTATED;
select * into ds_russell1000_positions_ROTATED
from #TEMP
Could someone help please?
Instead of this line:
SELECT * INTO #TEMP
Simply replace #TEMP with the name of the permanent table you wish to create.
Also take the # sign off the name of your CTE:
WITH
TEMP AS(
...
FROM TEMP
# signs are for naming temporary tables and should not be used in other object names.

How to display the table name in a union query

The following script is working well:
DECLARE #SelectClause VARCHAR(100) = 'SELECT id_contato'
,#Query VARCHAR(8000) = ''
SELECT #Query = #Query + #SelectClause + ' FROM ' + TABLE_NAME + ' UNION ALL '
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME LIKE '%zumbi' or TABLE_NAME like '%engajado%')
SELECT #Query = LEFT(#Query, LEN(#Query) - LEN(' UNION ALL '))
EXEC (#Query)
But I need a second column with the table name to identify where the information came from.
How can I do that?
You're utilizing the table_name field already in your query, just need to add it to your SELECT and quote it properly so it comes back as string literal:
DECLARE #SelectClause VARCHAR(100) = 'SELECT id_contato'
,#Query VARCHAR(8000) = ''
SELECT #Query = #Query + #SelectClause + ','''+Table_Name+''' AS Table_Name FROM ' + TABLE_NAME + ' UNION ALL '
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME LIKE '%zumbi' or TABLE_NAME like '%engajado%')
SELECT #Query = LEFT(#Query, LEN(#Query) - LEN(' UNION ALL '))
EXEC (#Query)
Updated quotes, works for me in SQL Server.

is any other way to do in dynamic pivot

while answering one question i got struck with other question in mind.when it is normal pivot it is working fine but if i'm trying to do Dynamic query when the problem arises
after answering he asked for Dynamic Pivot
PIVOT the date column in SQL Server 2012
if OBJECT_ID('tempdb..#temp') is not null
begin
drop table #temp
end
CREATE table #temp (dated varchar(10),E1 int,E2 int,E3 int,E4 int)
insert into #temp
(dated,E1,E2,E3,E4)values
('05-27-15',1,1,2,3),
('05-28-15',2,3,NULL,5),
('05-29-15',3,4,null,2)
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' + tbl.dated + ']'
FROM (
SELECT DISTINCT dated
FROM #temp
) AS tbl
SELECT #statement = 'Select P.col,MAX('+#columns+') from (
select col,' + #columns + ' from (
select * from #temp
CROSS APPLY(values(''E1'',E1),(''E2'',E2),(''E3'',E3),(''E4'',E4))cs (col,val))PP
PIVOT(MAX(val) for dated IN (' + #columns + ')) as PVT)P
GROUP BY P.COL
'
PRINT #statement
EXEC sp_executesql #statement = #statement
my problem is how can i take MAX() conditions for the all dates dynamically like
max(05-27-15),max(05-28-15) etc dates are coming dynamically how to assign max condition
Moving the MAX aggregate to column list variable will fix the issue
DECLARE #statement NVARCHAR(max),
#columns NVARCHAR(max),
#select_columns NVARCHAR(max)
SELECT #select_columns = Isnull(#select_columns + ', ', '')+ N'MAX([' + tbl.dated + '])'
FROM (SELECT DISTINCT dated
FROM #temp) AS tbl
SELECT #columns = Isnull(#columns + ', ', '') + N'[' + tbl.dated+ ']'
FROM (SELECT DISTINCT dated
FROM #temp) AS tbl
SELECT #statement = 'Select P.col,' + #select_columns
+ ' from (
select col,' + #columns
+ ' from (
select * from #temp
CROSS APPLY(values(''E1'',E1),(''E2'',E2),(''E3'',E3),(''E4'',E4))cs (col,val))PP
PIVOT(MAX(val) for dated IN (' + #columns
+ ')) as PVT)P
GROUP BY P.COL
'
PRINT #statement
EXEC sp_executesql #statement = #statement

Generating Scripts for Specific Records in SQL Server

This is probably a bit of a limited, but valuable scenario. I have a SQL Server 2008 database with a table that has millions of records. There appears to be an intermittent problem with several of the records. I'm trying to repro the problem. In an effort to do this, I finally got the ID of an offending record. I would like to generate an INSERT statement associated with this single record in my PROD database. Then I can easily migrate it into my TESTING database in an effort to repro and resolve the problem.
Basically, I need to generate a single INSERT statement for a single record from a single table where I know the primary key value of the record.
Does anyone have any ideas of how I can accomplish this? Essentially, I want to generate insert statements on a conditional basis.
Thank you!
First try to recreate what you want to insert with a SELECT statement.
After that you can insert into the table with a INSERT INTO like this:
INSERT INTO tablename
SELECT ....
If they are on different servers, you can use INSERT like this:
INSERT INTO tablename VALUES (...)
using the values given by the SELECT in the other server fill the values in the insert.
In your specific case I think you can do this:
CREATE PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + ' + REPLICATE(CHAR(39),3) + ','
+ REPLICATE(CHAR(39),3) + ' + ' + REPLICATE(CHAR(39),2) + '+'
+ 'RTRIM(' + CASE WHEN system_type_id IN (40,41,42,43,58,61) THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''
+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
ELSE 'REPLACE(' + QUOTENAME(name) + ','''''''','''''''''''')' END + ')
+ ' + REPLICATE(CHAR(39),2)
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39), 4) + ' + ' + STUFF(#vals, 1, 13, '')
+ REPLICATE(CHAR(39), 2);
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END
GO
So let's try it out:
CREATE TABLE dbo.splunge
(
ID INT, dt DATETIME, rv ROWVERSION, t NVARCHAR(MAX)
);
INSERT dbo.splunge(ID, dt, t)
SELECT 1, GETDATE(), 'foo'
UNION ALL SELECT 2, GETDATE(), 'bar'
UNION ALL SELECT 3, GETDATE(), 'O''Brien';
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 1;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '1','20120517 10:07:07:330','foo'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 2;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '2','20120517 10:07:07:330','bar'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 3;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '3','20120517 10:07:07:330','O''Brien'
If there is an IDENTITY column you may need to set SET IDENTITY_INSERT ON for the TEST table, and verify that there is no collision. Probably about 500 caveats I should mention, I haven't tested all data types, etc.
However in the more general case there is a lot more to it than this. Vyas K has a pretty robust stored procedure that should demonstrate how complicated it can get:
http://vyaskn.tripod.com/code/generate_inserts_2005.txt
You are probably far better off using a tool like Red-Gate's SQL Data Compare to pick a specific row and generate an insert for you. As I've blogged about, paying for a tool is not just about the money, it's about the hours of troubleshooting and bug-fixing that someone else has already done for you.
Aaron,
I liked your code, it solved a problem for me. I ran into a few issues using it (like you said I would) with nulls and the text type so I made some changes to address those issues.
ALTER PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + '','' + ' + 'ISNULL('+REPLICATE(CHAR(39),4)+'+RTRIM(' +
CASE WHEN system_type_id IN (40,41,42,43,58,61) -- datetime types
THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
WHEN system_type_id IN (35) -- text type NOTE: can overflow
THEN
'REPLACE(CAST(' + QUOTENAME(name) + 'as nvarchar(MAX)),'+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
ELSE
'REPLACE(' + QUOTENAME(name) + ','+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
END
+ ')+' + REPLICATE(CHAR(39),4) + ',''null'') + '
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39),2) + STUFF(#vals, 1, 6, '') + REPLICATE(CHAR(39),2) ;
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END