Exporting table parameter result as .txt file using stored procedure - sql

Is there a way that I could use for me to export the table parameter into .txt file in SQL Server?
Sample code that I did for trying to print out the
DECLARE #testTable TABLE (fld_Name VARCHAR(12), fld_Number VARCHAR(11))
DECLARE #fileTimeStamp varchar(200) = convert(varchar,getDate(), 112 )+'_'+ Replace(convert(varchar,getDate(), 114 ),':','') -- select convert(varchar, getdate(), 121)
DECLARE #fileExtension varchar(5) = 'txt'
INSERT INTO #testTable
SELECT [fld_Name] AS fld_Name,
[fld_Number] AS fld_Number
FROM TableBA tblBA
INNER JOIN TableCAS tblCAS ON
tblCAS.fld_Code = tblBA.fld_AccountNumber
WHERE [fld_Name] NOT IN (SELECT [fld_Name] FROM TableLeads)
declare #fn varchar(500) = 'D:/Test/Leads_'+#fileTimeStamp+'.'+#fileExtension;
declare #cmd varchar(8000) = concat('echo ', #testTable, ' > "', #fn, '"');
print #cmd
exec xp_cmdshell #cmd, no_output
set #cmd = concat('type "', #fn, '"');
print #cmd
exec xp_cmdshell #cmd;
Using that gives me an error of:
"Must declare the scalar variable "#testTable"
Is there a way that I could print the SELECT * results from the table parameter I created?

Try Like this:
declare #tablename varchar(100)='#testTable'
DECLARE #fileTimeStamp varchar(200) = convert(varchar,getDate(), 112 )+'_'+ Replace(convert(varchar,getDate(), 114 ),':','') -- select convert(varchar, getdate(), 121)
DECLARE #fileExtension varchar(5) = 'txt'
EXEC ('DECLARE '+#tablename+' TABLE (fld_Name VARCHAR(12), fld_Number VARCHAR(11)) ;
INSERT INTO '+#tablename+'
SELECT [fld_Name] AS fld_Name,
[fld_Number] AS fld_Number
FROM TableBA tblBA
INNER JOIN TableCAS tblCAS ON
tblCAS.fld_Code = tblBA.fld_AccountNumber
WHERE [fld_Name] NOT IN (SELECT [fld_Name] FROM TableLeads);
')
declare #fn varchar(500) = 'D:/Test/Leads_'+#fileTimeStamp+'.'+#fileExtension;
declare #cmd varchar(8000) = concat('echo ', #tablename, ' > "', #fn, '"');
print #cmd

Related

MSSMS - CSV file contains data but returns NULL with stored procedures

I have been trying my darndest to get the code described below to work. I am very inexpert at MSSMS and SQL. That said, I love the efficiency of SQL databases and would really love to make this code work.
I have tested my CSV files with this code:
BULK INSERT BCPData
FROM 'D:\cheese\bcp_test.csv'
WITH (FIRSTROW = 2,
FIELDTERMINATOR = ','
,ROWTERMINATOR = '0x0a'
);
GO
They import easily and the data appears.
However, if I try to use the code shown below (I need an code that automatically imports multiple CSV files into my table) I only get "NULL" results in the columns.
My query is as follows:
exec ImportFiles 'd:\cheese\' , 'd:\cheese\Archive' , 'bcp*.csv' , 'MergeBCPData'
I run this query after using the following code to create the necessary stored procedures:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[ImportFiles]') and `OBJECTPROPERTY(id, N'IsProcedure') = 1)`
drop procedure [dbo].[ImportFiles]
GO
create procedure ImportFiles
#FilePath varchar(1000) = 'd:\cheese\' ,
#ArchivePath varchar(1000) = 'd:\cheese\Archive\' ,
#FileNameMask varchar(1000) = 'bcp*.csv' ,
#MergeProc varchar(128) = 'MergeBCPData'
AS
set nocount on
declare #ImportDate datetime
select #ImportDate = getdate()
declare #FileName varchar(1000) ,
#File varchar(1000)
declare #cmd varchar(2000)
create table ##Import (s varchar(8000))
create table #Dir (s varchar(8000))
/*****************************************************************/
-- Import file
/*****************************************************************/
select #cmd = 'dir /B ' + #FilePath + #FileNameMask
delete #Dir
insert #Dir exec master..xp_cmdshell #cmd
delete #Dir where s is null or s like '%not found%'
while exists (select * from #Dir)
begin
select #FileName = min(s) from #Dir
select #File = #FilePath + #FileName
select #cmd = 'bulk insert'
select #cmd = #cmd + ' ##Import'
select #cmd = #cmd + ' from'
select #cmd = #cmd + ' ''' + replace(#File,'"','') + ''''
select #cmd = #cmd + ' with (FIELDTERMINATOR = '','''
select #cmd = #cmd + ',ROWTERMINATOR = ''0x0a''
)'
truncate table ##Import
-- import the data
exec (#cmd)
-- remove filename just imported
delete #Dir where s = #FileName
exec #MergeProc
-- Archive the file
select #cmd = 'move ' + #FilePath + #FileName + ' ' + #ArchivePath + #FileName
exec master..xp_cmdshell #cmd
end
drop table ##Import
drop table #Dir
go
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[MergeBCPData]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[MergeBCPData]
GO
create procedure MergeBCPData
AS
set nocount on
-- insert data to production table
insert BCPData
(
City ,
Visit_Duration_Seconds ,
Timezone ,
Most_Likely_Company
)
select
SUBSTRING('City', 1, 5),
SUBSTRING('Visit_Duration_Seconds', 1, 12),
SUBSTRING('Timezone', 1, 3),
SUBSTRING('Most_Likely_Company',1, 30)
from ##Import
go
Any help would be very appreciated. I'm hopeful it is just an error that my inexperienced eyes are too novel to catch. THANK YOU!
You stated 'I need an code that automatically imports multiple CSV files into my table'. Is there a pattern in the file names that you can exploit? Do the file names have dates in them, per chance? If there is some repeating pattern that you can exploit, like a series of dates, you can loop through all the files in your folder, and append all files to one table, in one go. Check out the code below, and post back if you have questions.
DECLARE #intFlag INT
SET #intFlag = 1
WHILE (#intFlag <=50) – we are running 50 loops...change this as needed
BEGIN
PRINT #intFlag
declare #fullpath1 varchar(1000)
select #fullpath1 = '''\\your_path_here\FTP\' + convert(varchar, getdate()- #intFlag , 112) + '_Daily.csv'''
declare #cmd1 nvarchar(1000)
select #cmd1 = 'bulk insert [dbo].[Daily] from ' + #fullpath1 + ' with (FIELDTERMINATOR = ''\t'', FIRSTROW = 5, ROWTERMINATOR=''0x0a'')'
exec (#cmd1)
SET #intFlag = #intFlag + 1
END
Here are some common date formats.
http://www.sql-server-helper.com/tips/date-formats.aspx
Again, I'm assuming you have dates in your file names.

T sql - How to store results from a dynamic query using EXEC or EXECUTE sp_executesql

I am trying to write a dynamic query. Let's say i have a table like below, which represents the hierarchy level of a sales agent:
AgentNumber Level1Agent Level2Agent Level3Agent Level4Agent Level5Agent
1122334455 1122334499 1122334488 1122334477 1122334466 1122334455
I want to be able to dynamically select a level based on a specified agent. My EXECUTE statement seems to work correctly, but how do I get the result stored in a variable I can use later? Every answer I have found seems to only get me a success return variable, not the actual query result.
Below is my code:
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT ' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, #up OUT
SELECT #up
The output of #up is NULL. If I change the last two lines to:
EXECUTE #up = sp_executesql #qry
SELECT #up
Now the output of #up is 0.
I want the output of 1122334499 and I need it stored in a variable that can later be used and inserted into a table.
Here is a fully functional example of how you can do this. Notice this is using a parameterized where clause and quotename around the column name in the dynamic sql to prevent sql injection.
if OBJECT_ID('tempdb..#Agents') is not null
drop table #Agents
create table #Agents
(
AgentNumber char(10)
, Level1Agent char(10)
, Level2Agent char(10)
, Level3Agent char(10)
, Level4Agent char(10)
, Level5Agent char(10)
)
insert #Agents
select '1122334455', '1122334499', '1122334488', '1122334477', '1122334466', '1122334455'
DECLARE #level INT = 3;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
declare #agentout char(10)
DECLARE #qry NVARCHAR(300) = 'SELECT #agent_out = ' + quotename(#colname) + ' FROM #Agents WHERE AgentNumber = #agentin';
EXECUTE sp_executesql #qry, N'#agentin char(10), #agent_out char(10) output', #agentin = #agent, #agent_out = #agentout output
select #agentout
You can try this :
DECLARE #level INT = 1;
DECLARE #agent CHAR(10) = 1122334455;
DECLARE #colname NVARCHAR(11) = CONCAT('Level',#level,'Agent');
DECLARE #whereclause NVARCHAR(35) = CONCAT('WHERE AgentNumber = ',#agent);
DECLARE #qry NVARCHAR(300) = 'SELECT #agentout=' + #colname + ' FROM dbo.TABLE ' + #whereclause;
DECLARE #up NVARCHAR(10);
EXECUTE sp_executesql #qry, N'#agentout NVARCHAR(10) OUTPUT', #agentout=#up OUTPUT
SELECT #up
Create a variable table and makes your query insert the results you want there. Something like this:
declare #results table(field1 varchar(max), field2 varchar(max));
declare #sqlStatement varchar(max);
set #sqlStatement = 'insert into #results(field1, field2) select field1, field2 from table';
EXECUTE #sqlStatement;
select * from #results; --It will print the results from your sql statement!

How to swap in a parameter for a specific VARCHAR value being used for a linked server with openquery

When I execute this query(it's a scalar function) I get the result I want. It returns a shipping number.
select ShipmentNo from openquery([SERVER_IP], 'SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo = ''G015246''')
However, when I swap out G015246 with the parameter #PO:
select #ShipmentLabels = ShipmentNo from openquery([SERVER_IP], 'SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo = ''#PO''')
For some reason the return value becomes null with this change.
My return statement for both is:
RETURN ISNULL(#ShipmentLabels, #PO)
where #ShipmentLabels is the desired return value. Since it is null it returns #PO instead, which ends up being G015246 which seems right.
Anyone notice anything wrong with how I've added the #PO parameter to the sql statement?
Stored Procedure that calls the Function(fnGetTheShippingLabels):
I guess the best way to describe this SP is the starting point.
ALTER PROCEDURE [dbo].[StartingSP]
#JobId INT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ErrorMsg VARCHAR(256)
SELECT OC.PoNo,
V.FirstName,
V.LastName,
dbo.fnGetTradeAppFacilityName(NULL,OC.PoNo) TradeAppFacilityName,
OC.ReportFileName, dbo.fnGetTheShippingLabels(NULL,OC.PoNo) ShippingLabels
FROM PoHdr P
INNER JOIN OrderConfirmation OC ON
OC.PoNo = P.PoNo
INNER JOIN CpVendor V ON
V.VendNo = P.VendNo
WHERE OC.JobId = #JobId
SELECT #ErrorMsg ErrorMsg
END
As you can see from above, the function is in the SELECT statement of the SP.
Complete Scalar Function:
ALTER FUNCTION [dbo].[fnGetTheShippingLabels]
(
#PoHdrRecId INT,
#PoNo VARCHAR(20)
)
RETURNS VARCHAR(220)
AS
BEGIN
DECLARE #PO VARCHAR(20)= #PoNo
DECLARE #ShipmentLabels VARCHAR(220)
select #ShipmentLabels = ShipmentNo from openquery([SERVER_IP], 'SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo = ''G015246''')
--FROM dbo.PoHdr WHERE PoNo = #PoNo
-- Return the result of the functionRETURN ISNULL(#ShipmentLabels, #PO)
END
Trying a different way of writing query now, this doesn't work fyi:
Declare #TSQL VarChar(8000)
set #TSQL = N'select #ShipmentLabels = ShipmentNo from openquery([SERVER_IP],SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo =' + #PO +''
exec sp_executesql #TSQL, N'#ShipmentLabels output', #ShipmentLabels = #ShipmentLabels out
I see that it can be done in two ways
Option 1
Creating a dynamic query and Passing the output parameter
Declare #TSQL VarChar(8000)
DECLARE #SQ VARCHAR(4) = ''''
DECLARE #paramDef VARCHAR(100)
set #TSQL = N'select #ShipmentLabels = ShipmentNo from openquery([SERVER_IP],SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo =' + #SQ + #PO + #SQ + ')'
SET #paramDef = N'#ShipmentLabels VARCHAR(1000) OUTPUT'
exec sp_executesql #TSQL, #paramDef, #ShipmentLabels = #ShipmentLabels OUTPUT
Option 2 Creating a dynamic query, getting the value into a temp table and the read the value from temporary table.
Declare #TSQL VarChar(8000)
DECLARE #SQ VARCHAR(4) = ''''
DECLARE #ShipmentNo VARCHAR(1000)
set #TSQL = N'select ShipmentNo from openquery([SERVER_IP],SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo =' + #SQ + #PO + #SQ + ')'
CREATE TABLE #T
(
temp VARCHAR(max)
)
INSERT INTO #T
EXEC(#TSQL)
SELECT #ShipmentNo = temp from #t
SELECT #ShipmentNo
drop table #t
The complete solution with your stored procedure will look like, I have written it with a cursor and all, it can still be improved for performance, but with our limited on your DB design this is best solution we can provide for you.
ALTER PROCEDURE [dbo].[StartingSP]
#JobId INT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ErrorMsg VARCHAR(256)
DECLARE #PoNO VARCHAR(1000)
Declare #TSQL VarChar(8000)
DECLARE #SQ VARCHAR(4) = ''''
DECLARE #ShipmentNo VARCHAR(1000)
set #TSQL = N'select ShipmentNo,' + #SQ + #PO + #SQ +' as PoNo from openquery([SERVER_IP],SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo =' + #SQ + #PO + #SQ + ')'
CREATE TABLE #T1
(
temp VARCHAR(max)
)
INSERT INTO #T1
EXEC(#TSQL)
SELECT OC.PoNo,
V.FirstName,
V.LastName,
dbo.fnGetTradeAppFacilityName(NULL,OC.PoNo) TradeAppFacilityName,
OC.ReportFileName
,'' as
--, dbo.fnGetTheShippingLabels(NULL,OC.PoNo) ShippingLabels
INTO #T
FROM PoHdr P
INNER JOIN OrderConfirmation OC ON
OC.PoNo = P.PoNo
INNER JOIN CpVendor V ON
V.VendNo = P.VendNo
WHERE OC.JobId = #JobId
Declare #TSQL VarChar(8000)
DECLARE #SQ VARCHAR(4) = ''''
DECLARE #ShipmentNo VARCHAR(1000)
CREATE TABLE #T1
(
PoNo VARCHAR(1000),ShipmentNo VARCHAR(max)
)
DECLARE vend_cursor CURSOR
FOR SELECT PoNO FROM #T
OPEN vend_cursor
FETCH NEXT FROM vendor_cursor
INTO #PoNO
WHILE ##FETCH_STATUS = 0
BEGIN
set #TSQL = N'select ShipmentNo,' + #SQ + #PO + #SQ +' as PoNo from openquery([SERVER_IP],SET FMTONLY OFF EXEC GsvStaging.dbo.Paul_GetPoShippingLabels #CartId = NULL, #CpPoNo =' + #SQ + #PO + #SQ + ')'
INSERT INTO #T1
EXEC(#TSQL)
FETCH NEXT FROM vendor_cursor
INTO #PoNO
END
CLOSE vendor_cursor
DEALLOCATE vendor_cursor
UPDATE T
SET T.ShippingLabels = T1.ShipmentNo
FROM #T T
JOIN #T1 T1
ON T.PoNo = T1.PoNo
SELECT #ErrorMsg ErrorMsg
END

Can I use variable in condition statement as value with where condition that test that value

I have the following stored procedure:
ALTER proc [dbo].[insertperoll] #name nvarchar(50) , #snum int , #gnum int
as
DECLARE #value nvarchar(10)
SET #value = 's'+CONVERT(nvarchar(50),#snum)
DECLARE #sqlText nvarchar(1000);
DECLARE #sqlText2 nvarchar(1000);
DECLARE #sqlText3 nvarchar(1000);
declare #g nvarchar(50) = '''g1'''
SET #sqlText = N'SELECT ' + #value + N' FROM dbo.GrideBtable'
SET #sqlText2 = ' where Gnumber = '+#g --here is the problem it error invalid column name -- the #g is value from the table condition
set #sqlText3 = #sqlText+#sqlText2
Exec (#sqlText3) -- here how can i save the result of the exec into varibale
declare #sal nvarchar(50) = #sqlText3
insert employ (name,Snumber,Gnumber,Salary) values(#name,#snum,#gnum,#sal)
QUESTION: How to put in condition variable gets value from the table when i exec it it think that the #g is column but its not its a value from the table to test it so i display one value after the exec the other QUESTION is how to save the result from the exec in variable and then use that value
I'm using SQL Server 2008 (9.0 RTM)
This will be a stored procedure
Thanks in advance
Not sure why you would go through all the loops to insert into the table where you can have a simple insert query like ..
ALTER PROC dbo.[insertperoll] #name nvarchar(50) , #snum int , #gnum int
AS
insert employ (name, Snumber, Gnumber, Salary)
select #name
, #sum
, #gnum
, case when #snum = 1 then s1
when #snum = 2 then s2
when #snum = 3 then s3
when #snum = 4 then s4
end as Salary
from dbo.GrideBtable
where Gnumber = #gnum
If your intent is to have the proc retrieve a salary value from a column determined from the parameter snum and then make an insert into employ using the values passed as parameters and the salary retrieved I think you could refactor your procedure to this:
CREATE proc [dbo].[insertperoll] #name nvarchar(50) , #snum int , #gnum int AS
DECLARE #g NVARCHAR(50) = 'g1'
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'INSERT employ (name,Snumber,Gnumber,Salary) '
SET #sql += N'SELECT ' + QUOTENAME(#name, '''')
SET #sql += N', ' + CAST(#snum AS NVARCHAR(50))
SET #sql += N', ' + CAST(#gnum AS NVARCHAR(50))
SET #sql += N', s' + CAST(#snum AS NVARCHAR(50))
SET #sql += N' FROM dbo.GrideBtable'
SET #sql += N' WHERE Gnumber = ' + QUOTENAME(#g, '''')
EXEC (#sql)
Of course you could add the #g variable to the procedure parameters instead of having it hard coded in the procedure and call it as:
EXEC insertperoll #name='john', #snum=10, #gnum=100, #g='g1'
Sample SQL Fiddle (with some assumptions made about table structure)
You could do this using sp_executesql instead of exec() since this will allow you to use parameters, you can use an output parameter to get the value from the query:
DECLARE #SQL NVARCHAR(MAX) = N'SELECT #val = ' + CONVERT(NVARCHAR(10),#snum) +
N' FROM dbo.GrideBtable WHERE Gnumber = #G1';
DECLARE #val INT; -- NOT SURE OF DATATYPE REQUIRED
EXECUTE sp_executesql #SQL, N'#G1 VARCHAR(20), #val INT OUT', 'G1', #val OUT;

Sql multiple file import

I want to insert multiple csv file to sqlserver table. I have a procedure for doing that. It works but my all files have same column name. So instead of importing all records it just imports column name which is the first row. If I manually delete first row then it imports the other records, I have thousands of files so I cant work manually. I am posting store procedure here. Please tell me if I can change something to make this work.
ALTER procedure [dbo].[usp_ImportMultipleFiles] #filepath varchar(500),
#pattern varchar(100), #TableName varchar(128)
as
set quoted_identifier off
declare #query varchar(1000)
declare #max1 int
declare #count1 int
Declare #filename varchar(100)
set #count1 =0
create table #x (name varchar(200))
set #query ='master.dbo.xp_cmdshell "dir '+#filepath+#pattern +' /b"'
insert #x exec (#query)
delete from #x where name is NULL
select identity(int,1,1) as ID, name into #y from #x
drop table #x
set #max1 = (select max(ID) from #y)
--print #max1
--print #count1
While #count1 <= #max1
begin
set #count1=#count1+1
set #filename = (select name from #y where [id] = #count1)
set #Query ='BULK INSERT '+ #Tablename + ' FROM '''+ #Filepath+#Filename+'''
WITH ( FIELDTERMINATOR = '','',ROWTERMINATOR = ''\n'')'
--print #query
exec (#query)
insert into logtable (query) select #query
end
drop table #y
You can use the First Row option in your bulk insert statement something like...
BULK INSERT Table_Name
FROM 'C:\FilePath'
WITH
(
FIELDTERMINATOR = ','
,ROWTERMINATOR = '\n'
,FIRSTROW = 2 --<-- This option here
)
Edit to your proc
DECLARE #Query NVARCHAR(MAX);
SET #Query = N'BULK INSERT '+ #Tablename +
N' FROM '''+ #Filepath+#Filename +
N''' WITH ( FIELDTERMINATOR = '',''
,ROWTERMINATOR = ''\n''
,FIRSTROW = 2
)'