How to pass multiple values in where statement in SSIS variable? - sql-server

I'm creating a SSIS package which has two variables that is going to assign values into another SQL Command variable. The data source is an ODBC connector and the destination is an OLEDB connector.
Variables name:
vPurchaseType (multiple values)
vTransactionDate (single value)
vPSourceQuery (SQL statement that is receive the others two variables)
One variable is a single row, this one it's working. The other variable is multiple values that is going to be ingested in a IN clause. But I'm not being able to pass multiple values in this one, I already tried Single row or Full result set but also doesn't work.
First variable result (vPurchaseType):
Query example:
SELECT Head FROM TableB
Head
12
9C
AA
The second variable must be between single quotes in order to work.
Second variable result (vTransactionDate):
Query example:
SELECT Head FROM TableA
Head
2020-01-01
Third variable:
SELECT
ColA,
ColB,
ColC,
ColD
FROM TableC
WHERE ColC >= '"+ #[User::vTransactionDate] + "'
AND ColD IN ("+ #[User::vPurchaseType] +")
My package:

Basically I'm using the solution of this article from MyTecBits - SQL Server: Concatenate Multiple Rows Into Single String, and applying that to my variable vPurchaseType, and receiving the values as Single Row. But I had to change the query a little bit, by using the function CAST AS VARCHAR (4000) to accept all the data from my column.
After that I changed my Data Flow, and did the swap from OLEDB Destination to ADO Net Destination, I also had to mark the option ValidadeExternalMetadata as False, and that's it! Now is working.

Related

How to pass a parameter in a SQL query in MS SQL Server from an Excel sheet

Let's say I have this query in SQL Server:
select *
from Table1
where Column1 IN ('01061120192T')
I want to pass the values for Column1 from a column in an Excel sheet.
I'm able to pass a single value to the query as mentioned here. But parenthesis of IN can accept multiple values so I want to pass 1000 values in the parenthesis from a column in an Excel sheet.
Tried to pass multiple values to the parameter as below, but that's not working.
=Sheet1!$G$1:$G$5
You pass variables in SSIS as a ?, and then define your variables in your parameter mapping pane.
select *
from Table1
where Column1 = ?
Then, you need to go to your Parameter mapping pane and click Add. Select your variable's name in the Variable name Column. Then Input as the direction. Leave Paramter Size as -1.

How can I differ between variables in SQL Tasks in a Workflow?

I have a task that will enter the run-id, table name and row-count into a logging table. I have 6 tables in total, and expecting 15 more tables in the next sprint.
The SQL looks as follows:
INSERT INTO logging_rowcount (RUN_ID, tablename, row_count) values (?, 'hardcoded_name1', ?);
INSERT INTO logging_rowcount (RUN_ID, tablename, row_count) values (?, 'hardcoded_name2', ?);
etc, for a total of 6 INSERT INTO statements.
I mapped the parameters accordingly, using the variable "run-id" for every 2nd parameter. The task itself works, however I fear this becomes little unmaintainable when I have 21 tables (and 42 parameter mappings).
While this particular case can be solved with another loop, generally speaking:
Is there a way to use "speaking" terms for my variables? E.G.
INSERT INTO logging_rowcount (RUN_ID, tablename, row_count) values (#USER:run_id, #USER:tablename, #User:rowCount_table)
You can declare variables in the script task:
DECLARE #RunID INT = ?;
INSERT INTO .... VALUES (#RunID, ?, ...);
INSERT INTO .... VALUES (#RunID, ?, ...);
Now your first parameter will be the RunID and all subsequent ones are the row counts.
You can define a SQL variable in the script for all package variables if you want, so the mapping will be easier to understand (it will be in order in both the mapping and in the script, so easy to match).
You can also have the query as an expression (by having a string variable which stores the query) and in the expression you can use the parameter/variable names, but that will be prone to SQL Injection.

Turning a multi-value parameter into a temp table in SQL Server Business Intelligence Development Studio

I want to create a report in MS SQL Server BIDS (SSMS and Visual Studio). The user would enter a list of email addresses as a parameter. So #pEmails would be 'foo#bluh.com', 'bar#meh.org', etc. These email addresses may or may not be in a table.
I can simply do:
and Table.Email in (#pEmails)
and that works, except I need to return the email address if it's NOT found as well. So the results would be something like:
|email |found in table|
|------------|--------------|
|foo#bluh.com| Y |
|bar#meh.org | N |
I was thinking I could take the list of values entered as the #pEmails parameter and create a temp table with them, which I could then left join with, but my attempts to do so have not worked out.
declare #pEmails table (EmailAddress varchar(255));
insert into #pEmails values (#ReportParameter1);
select
*
from
#pEmails
The above works if only a single value is put into #ReportParameter1, but not if multiples are in it.
I am using SQL Server 2008. Any suggestions on how best to proceed?
As has been stated, you need some kind of split function, for analysis on the performance of various methods Split strings the right way – or the next best way is an excellent read. Once you have your function, you then need to define your query parameter as a string, rather than a table:
So your query would actually become:
DECLARE #pEmails TABLE (EmailAddress varchar(255));
INSERT #pEmails (EmailAddress)
SELECT Value
FROM dbo.Split(#pEmallString);
Then go to your dataset properties, and instead of passing the multivalue parameter #pEmails to the dataset, instead create a new one #pEmailString, and set the value as an expression, which should be:
=Join(Parameters!pEmails.Value, ",")
This turns your multivalue parameter into a single comma delimited string. It seems pretty backwards that you need to convert it to a delimited string, only to then split it in SQL, unfortunately I don't know of a better way.
Here are some learnings on this topic (standing on the shoulders of the information elsewhere in this thread).
Set a parameter (select 'multiple values' checkbox):
InputList
Establish dataset query:
SELECT *
INTO #InputTemp
FROM STRING_SPLIT(#InputListJoin, ',')
SELECT value as ValueName
FROM #InputTemp T2
WHERE NOT EXISTS (
SELECT MyValue
FROM MyTable T1
WHERE T1.MyValue = T2.value
)
Establish dataset parameters:
Name: #InputList | Value: [#InputList]
Name: #InputListJoin | Value(expression): =Join(Parameters!InputList.Value,",")
The element names can be changed as needed.
Somewhat on topic, other details that might be helpful:
[#InputList.IsMultiValue] --> true/false whether your parameter is multi-value (not whether there are multiple values)
[#InputList.Count] --> count of items in input list (excludes blank lines)
=Parameters!InputList.Value(2) --> return third value from list (counting from zero)

SSIS SQL TASK MAX(DATE) to Variable in DATA FLOW

OK this seems like it should be insanely easy, but I cannot figure it out. Every where I look online says to create temp tables and VB scripts and I cannot believe I have to do that. My goal is to insert all the records in a table with a date later than the max date in that destination table.
UPDATE The 2 tables are in two different non linked SQL databases
So:
Select #[User::Dated] = MAX(Dateof) from Table2
Insert into Table2
Select *
From Table1
Where DateOf > #[User::Dated]
I am trying to do this in SSIS. I declared a variable, the SQL execution step looks like it is assigning the single row output to it. But when I got go into the data flow it give me no parameters to choose, when I force the known parameter which is in the project scope it says no parameter exists
Create two OLE DB data sources each pointing at you two databases.
Create a variable called max_date and make its data type String.
Place an Execute SQL Task on the Control Flow, change its connection type to OLE DB and for the connection select the name of the data source that contains Table2. Set the ResultSet to Single Row. Add the following for the SQLStatement:
SELECT CAST(MAX(Dateof) AS VARCHAR) AS max_date FROM Table2
Go to the Result Set pane, click Add and enter the following:
Result Name: max_date
Variable Name: User::max_date
You can now use the max_date variable in an expression to create a SQL statement, for example you could use it in another Execute SQL Task which would use the second Data Connection like so:
"INSERT INTO Table2
SELECT *
FROM Table1
WHERE DateOf > '" + #[User::max_date] + "'"
Or in an OLE DB Source in a data flow like so:
"SELECT *
FROM Table1
WHERE DateOf > '" + #[User::max_date] + "'"
You can do this in a single SQL Task if you want:
Insert into Table2
Select *
From Table1
Where DateOf > (Select MAX(Dateof) from Table2)
If you want to use multiple Execute SQL Task items in the control flow, or want to make use of the parameter in a data flow instead, you have to change the General > Result Set option for your MAX() query to Single Row, then move from General to Result Set and Add a new variable for your result set to occupy.
To use that variable in your INSERT INTO.... query via Execute SQL Task, you'll construct your query with a ? for each parameter and map them in the parameter mapping section. If a variable is used multiple times in a query it's easiest to use a stored procedure, so you can simply pass the relevant parameters in SSIS.

SQL Server insert or query between servers ingnores column in table starting with a number?

I am trying to query between two servers which have identical tables (used the same create statement for both). When I try to insert the results from Server A to Server B I get an error indicating "Column name or number of supplied values does not match table definition."
Query run on server A
Insert into ServerB.Database1.dbo.Table1
Select *
from Table1
The error is clear, but what isn't clear is the reason that it is generated. The definitions of the two tables are identical. What I was finally able to isolate was a table name that starts with a numeric value is not being recognized.
When I run this on ServerA:
Select *
from ServerB.Database1.dbo.Table1
The field with the numeric value is not shown in the results set of they query. The short term fix was to rename the field in the database, but why is this happening?
I am curious about the collation too, but really the answer is to wrap the object names in square brackets. i.e. SELECT [1col], [2col], [etc] FROM [1database].[2owner].[3table]. This way SQL with recognize each as an object name and not a function.
One other thing to keep in mind is to not use splat (*) in your select statement, this has potential problem of it's own. For example, you could run into an error in your Insert if the ServerA's table1 structure was change and ServerB's table one stayed the same.

Resources