SQL Server remove trailing comma from XML path - sql-server

I have the following code that pulls what my columns are called within a given table of mine:
SELECT
column_name + ','
FROM
information_schema.columns
WHERE
table_name = 'maintReq'
FOR XML PATH('')
And I am wanting to place that into my current query:
SET IDENTITY_INSERT maintReq ON;
GO
INSERT INTO maintReq
OUTPUT Inserted.ID
VALUES ((SELECT ISNULL(MAX(id) + 1, 0)
FROM maintReq WITH(SERIALIZABLE, UPDLOCK)
),'MAYBE', 'true');
SET IDENTITY_INSERT maintReq OFF;
I've tried to do the following myself:
SET IDENTITY_INSERT maintReq ON;
GO
INSERT INTO maintReq (
SELECT
column_name + ','
FROM
information_schema.columns
WHERE
table_name = 'maintReq'
for
xml path('')
)
OUTPUT Inserted.ID
VALUES (
(
SELECT
ISNULL(MAX(id)+1,0)
FROM
maintReq WITH(SERIALIZABLE, UPDLOCK)
),'MAYBE', 'true'
);
SET IDENTITY_INSERT maintReq OFF;
But with that I am getting the error of:
Msg 156, Level 15, State 1, Line 4
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 8
Incorrect syntax near ')'.
Msg 102, Level 15, State 1, Line 16
Incorrect syntax near ','.
Not sure if that error is called by the extra comma that was added to the output of the XML path or if its something else?
My full stored procedure looks like this:
DECLARE #SQLQuery VARCHAR(MAX);
SET #SQLQuery = 'SET IDENTITY_INSERT ' + #val1 + ' ON
INSERT INTO ' +
#val1 + '
OUTPUT Inserted.ID
VALUES ' +
'(
(
SELECT
ISNULL(MAX(id)+1,0)
FROM
' + #val1 + ' WITH(SERIALIZABLE, UPDLOCK)
),''' + #val2 + ''', ''' + #val3 + '''
) ' +
'SET IDENTITY_INSERT ' + #val1 + ' OFF;'
EXEC [dbo].[_chkQ] #SQLQuery
The above SP is what I am currently getting this error:
An explicit value for the identity column in table 'maintReq' can only
be specified when a column list is used and IDENTITY_INSERT is ON.
Thanks to #Pரதீப் this is the final working query code:
SET #SQLQuery = 'SET IDENTITY_INSERT ' + #val1 + ' ON
INSERT INTO ' + #val1 + '(' +
Stuff(
(SELECT
',' + quotename(column_name)
FROM
information_schema.columns
WHERE
table_name = '' + #val1 + ''
FOR xml path('')
), 1, 1, ''
) +
')
OUTPUT Inserted.ID
VALUES ' +
'(
(
SELECT
ISNULL(MAX(id)+1,0)
FROM
' + #val1 + ' WITH(SERIALIZABLE, UPDLOCK)
),''' + #val2 + ''', ''' + #val3 + '''
) ' +
'SET IDENTITY_INSERT ' + #val1 + ' OFF;'

You need to use dynamic sql
DECLARE #col_list VARCHAR(8000)= ''
SET #col_list = Stuff((SELECT ',' + quotename(column_name) --"quotename" is to escape illegal characters
FROM information_schema.columns
WHERE table_name = 'maintReq'
FOR xml path('')), 1, 1, '')
SET IDENTITY_INSERT maintReq ON;
EXEC ('
INSERT INTO maintReq ('+#col_list+')
OUTPUT Inserted.ID
VALUES (
(SELECT
ISNULL(MAX(id)+1,0)
FROM
maintReq WITH(SERIALIZABLE, UPDLOCK)
),''MAYBE'', ''true''
); ')
SET IDENTITY_INSERT maintReq OFF;

Related

SQL Server Export to CSV with Headings

I have a stored procedure begin called like this:
EXEC spExportData_n 'dbName', #SQL, #FileName
where #SQL is the SQL statement and #FileName is the file location.
It works great, however, the column headings appear randomly in the file. How can I make it so that the column headings are always the first row?
Here is the stored procedure:
CREATE PROCEDURE [dbo].[spExportData_n]
(#dbName varchar(100),
#sql varchar(8000),
#fullFileName varchar(1000))
AS
IF #sql = '' or #fullFileName = ''
BEGIN
SELECT 0 AS ReturnValue -- failure
RETURN
END
-- if DB isn't passed in set it to master
SELECT #dbName = 'use ' + #dbName + ';'
IF object_id('##TempExportData') IS NOT NULL
DROP TABLE ##TempExportData
IF object_id('##TempExportData2') IS NOT NULL
DROP TABLE ##TempExportData2
-- insert data into a global temp table
DECLARE #columnNames varchar(8000),
#columnConvert varchar(8000),
#tempSQL varchar(8000)
SELECT #tempSQL = LEFT(#sql, CHARINDEX('from', #sql)-1) + ' into ##TempExportData ' +
substring(#sql, charindex('from', #sql)-1, len(#sql))
exec(#dbName + #tempSQL)
if ##error > 0
begin
select 0 as ReturnValue -- failure
return
end
-- build 2 lists
-- 1. column names
-- 2. columns converted to nvarchar
SELECT #columnNames = COALESCE( #columnNames + ',', '') + column_name,
#columnConvert = COALESCE( #columnConvert + ',', '') + 'convert(nvarchar(4000),'
+ column_name + case when data_type in ('datetime', 'smalldatetime') then ',121'
when data_type in ('numeric', 'decimal') then ',128'
when data_type in ('float', 'real', 'money', 'smallmoney') then ',2'
when data_type in ('datetime', 'smalldatetime') then ',120'
else ''
end + ') as ' + column_name
FROM tempdb.INFORMATION_SCHEMA.Columns
WHERE table_name = '##TempExportData'
-- execute select query to insert data and column names into new temp table
SELECT #sql = 'select ' + #columnNames + ' into ##TempExportData2 from (select ' + #columnConvert + ', ''2'' as [temp##SortID] from ##TempExportData union all select ''' + replace(#columnNames, ',', ''', ''') + ''', ''1'') t order by [temp##SortID]'
exec (#sql)
-- build full BCP query
DECLARE #bcpCommand VARCHAR(8000)
SET #bcpCommand = 'bcp " SELECT * from ##TempExportData2" queryout'
SET #bcpCommand = #bcpCommand + ' ' + #fullFileName + ' -c -t, -U ***-P ****-c'
EXEC MASTER..xp_cmdshell #bcpCommand
if ##error > 0
begin
select 0 as ReturnValue -- failure
return
end
drop table ##TempExportData
drop table ##TempExportData2
set #columnNames =' '
set #columnConvert =' '
set #tempSQL =' '
select 1 as ReturnValue

Openquery with TSQL: how to insert NULL in nvarchar column?

Im trying to use a stored procedure to insert some string values into a remote DB with Openquery. The argument #val_a can sometimes be some random string, but sometimes it can be NULL.
Following syntax works if #val_a is NULL, but not if it's a string 'asdf'.
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
val_a = ' + ISNULL(convert(VARCHAR(MAX), #val_a), 'NULL') + ';'
EXEC (#TSQL)
But, in order to work with the string 'asdf', the syntax has look like this:
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
val_a = ''' + ISNULL(convert(VARCHAR(MAX), #val_a), 'NULL') + ''';'
EXEC (#TSQL)
But here, NULLs are inserted as the string 'NULL', not as a NULL value.
Is there a way to write the TSQL query in such form that both NULL and 'asdf' are inserted correctly in the table?
You may use like that:
val_a = ' + ISNULL(convert(VARCHAR(MAX), '''' + #val_a + ''''), 'NULL') + ';'

Turn on and off the IDENTITY_INSERT before and after insert dynamically

select
row_number() over (order by 1) as rn, *
into
#execute_insert
from
#finaldata
where
noofrows > 0;
declare #intmin int, #intmax int
select #intmin = min(rn), max(rn)
from #execute_insert
begin
declare #query nvarchar(max) ='';
select #query = concat('ALTER TABLE ' + table_Name + 'NOCHECK CONSTRAINT All ')
If set Identity_Insert ON
select #query = 'insert Into' + #Table_Name + ' '+ #column_Name
+' select ' + #Column_Name
+' from '+#Table_Name+' '+ sql_query+''
Else Identity_insert Off
end
It is not possible to toggle your Identity_Insert in SQL. However you may achieve the same by using dynamic sql. Everytime when you are inserting some data in a table, set Identity_Insert ON for that table and close it after executing your query.
You can make both ON and OFF in one command, to make sure that it is always in closed state after execution of query.
.
.
.
-- your code
SET #query = 'SET IDENTITY_INSERT ' + #Table_Name + ' ON '
SET #query = #query + ' insert Into' + #Table_Name + ' '+ #column_Name
+' select ' + #Column_Name
+' from '+#Table_Name+' '+ sql_query+''
SET #query = #query + ' SET IDENTITY_INSERT ' + #Table_Name + ' OFF '
EXEC (#query )
.
.
.
Note: I am not checking your query, hope that works fine individually, this is example to set IDENTITY_INSERT ON and OFF in single query statement.

SQL Server 2008 R2: Invalid column name in PIVOT query

I have a dynamic pivot query and I want to pivot on businessaccountnumber which I know exist in the transaction_table but it keeps returning that "Invalid column name 'bizi'."- for line 1.
DECLARE #Output nvarchar(max) = N''
DECLARE #PivotList varchar(max)
SELECT
#PivotList = COALESCE(#PivotList + ', ', N'') + N'[' + bizid + N']'
FROM (SELECT DISTINCT
BusinessAccountNumber [bizid]
FROM transaction_table
WHERE postingdate BETWEEN '1/01/2015' AND '2/01/2015'
) AS CustProds;
SET #Output = 'SELECT [bizName],[bizi]
, ' + #PivotList + '
FROM ( select businessname as [bizName],businessaccountnumber as [bizi],
sum((Transactionamount*(-1))) as [Transactionamount]
FROM transaction_table
WHERE postingdate between ''1/01/2015'' and ''2/01/2015''
GROUP BY businessaccountnumber,businessname) as P
PIVOT ( SUM(Transactionamount) FOR P.bizi IN (' + #PivotList + ') ) AS PVT'
EXEC sp_executesql #Output;
EDIT: Thanks to Backs for pointing out my error but now I have a new error.
the output I am looking for is:
Date | bizid12| bizid13| bizid14...
01/01/2015| $1 | $3 | $56
01/02/2015| $12 | $34 | $3
.....
DECLARE #Output nvarchar(max) = N''
DECLARE #PivotList varchar(max)
SELECT
#PivotList = COALESCE(#PivotList + ', ', N'') + N'[' + bizid + N']'
FROM (SELECT DISTINCT
BusinessAccountNumber [bizid]
FROM transaction_table
WHERE postingdate BETWEEN '1/01/2015' AND '2/01/2015'
) AS CustProds;
SET #Output = 'SELECT [sp_date]
, ' + #PivotList + '
FROM ( select Convert(varchar,postingdate,101) as [sp_date]
,businessaccountnumber as [bizi],
sum((Transactionamount*(-1))) as [Transactionamount]
FROM transaction_table
WHERE postingdate between ''1/01/2015'' and ''2/01/2015''
GROUP BY businessaccountnumber) as P
PIVOT ( SUM(Transactionamount) FOR P.bizi IN (' + #PivotList + ') ) AS PVT'
EXEC sp_executesql #Output;
Error now says:
Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'Qry12090'.
Msg 1056, Level 15, State 1, Line 1
The number of elements in the select list exceeds the maximum allowed number of 4096 elements.
You can't select bizi in query SELECT [bizName],[bizi] using it in PIVOT FOR P.bizi IN. Remove [bizi] from select statement

Insert script for a particular set of rows in SQL

I am using SQL Server 2008. I use to take the script of my data from SQL table using Tasks --> Generate Scripts option.
Here is my problem:
Let's say I have 21,000 records in Employee table. When I take the script of this table, it takes the insert script for all 21000 records. What is the solution if I want to take only the script of 18000 records from the table?
Is there any solution using SQL query or from the tasks wizard?
Thanks in advance...
Create a new View where you select your desired rows from your Employee table e.g. SELECT TOP 21000...
Then simply script that View instead of the Table.
In case the views are not an option for you I wrote the following code based on the Aaron Bertrand's answer here that will give the insert statement for a single record in the db.
CREATE PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value NVARCHAR(10) -- 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) -- dateteime and time stamp type
THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
WHEN system_type_id IN (35) -- text type
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
I took the above code and wrapped it the following proc that will use the where clause you give it to select which insert statements to create
CREATE PROCEDURE dbo.GenerateInserts
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#whereClause NVARCHAR(500) -- the where clause used to parse down the data
AS
BEGIN
declare #temp TABLE ( keyValue nvarchar(10), Pos int );
declare #result TABLE ( insertString nvarchar(MAX) );
declare #query NVARCHAR(MAX)
set #query =
'with qry as
(
SELECT ' + #pk_column + ' as KeyValue, ROW_NUMBER() over(ORDER BY ' + #pk_column + ') Pos
from ' + #table + '
' + #whereClause + '
)
select * from qry'
insert into #temp
exec sp_sqlexec #query
Declare #i int, #key nvarchar(10)
select #i = count(*) from #temp
WHILE #i > 0 BEGIN
select #key = KeyValue from #temp where Pos = #i
insert into #result
exec [dbo].[GenerateSingleInsert] #table, #pk_column, #key
set #i = #i - 1
END
select insertString from #result
END
Calling it could look like the following. You pass in the table name, the table primary key and the where clause and you should end up with your insert statements.
set #whereClause = 'where PrettyColorsId > 1000 and PrettyColorsID < 5000'
exec [dbo].GenerateInserts 'dbo.PrettyColors', 'PrettyColorsID', #whereClause
set #whereClause = 'where Color in (' + #SomeValues + ')'
exec [dbo].GenerateInserts 'dbo.PrettyColors', 'PrettyColorsID', #whereClause

Resources