Newbie question. I believe this is one of the most common errors. I found several of them on msdn forum itself but probably there are many ways on achieving this error? Please help.
I am trying to move and rename some images from one folder to another (and yes I have seen the blog by Rafael Salas and many others but none of them helps).
Like moving from \server1\images\123-456.jpg to \server2\images\123456.jpg
I am using a foreach.
Source variable is built dynamically. In the first iteration #imagePath = \server1\images\123-456.jpg ( i checked using messagebox.show)
I have defined #remoteImagePath = \server2\images\ (which never changes) and #revisedImageName = 123456.jpg (built dynamically in script task using string replace - also checked using messagebox.show)
In FileSystem Task, I am using SourceVariable as #imagePath and using Expressions to define Destination as in #[User::remoteImagePath] + "\" + #[User::revisedImageName]
Dont know for what reason, I am getting this error
Failed to lock variable "\server2\images\123456.jpg" for read access with error 0xC0010001 "The variable cannot be found. This occurs when an attempt is made to retrieve a variable from the Variables collection on a container during execution of the package, and the variable is not there. The variable name may have changed or the variable is not being created.".
Set the IsSourcePathVariable to True and set the SourceVariable to a SINGLE variable.
If you use the expression editor to set Source using multiple variables, or anything else apart from a SINGLE variable it will not work. If you want to concatenate hard-coded strings to variables, or multiple variables, do this by creating a new variable in the package, and use the Expressions tab in the variables tab to build the variable as a single variable.
I believe expressions editor needs syntax
#[User::remoteImagePath] + "\\" + #[User::revisedImageName]
Related
Any help is much appreciated. I am trying to create an SSIS package to loop through files in the folder and get the Path + filename and finally execute the stored proc with parameter as path+filename. I am not sure how to get the path+filename and insert the into the Stored proc as parameter. I have attached the screenshot for your reference:
Looks like you have the right idea in general and the link #Speedbirt186 provided has some good details but it sounds like there are a couple of nuances that I thought I might point out in regards to flow and variables.
The foreach loop can assign the entire path or the file name or file name & extension to a variable. The latter will be the most help in your case if you don't want to add a script task to split the Filename from the path. If you start by adding 5 variables to your project it will make it a little easier. 1 will be the Source Directory Path, another the Destination (Archive) Directory Path, and then 1 to hold the File Name and Extension assigned by the for each loop. Then 2 additional dynamic variables that simply combine the source directory and file name to get the source full path and the destination with file name to get the destination full path.
Next make sure you set up your database and Excel file connections. In your Excel file connection after setting it up go to Expressions in the properties window and set the "Connection String" property to SourceFullPath. This will tell the connection to change the file path at every iteration of your loop.
Now you just need to setup your loop etc. Add the fore each loop container setting a directory, filter, and choose File Name and Extension.
Now in the expression box on the collection page set the directory property to be that of your Source Directory variable.
The last part of the Fore each loop is to set your variable mappings to store the file name in your variable. so go to that tab choose your file name variable and set index to 0.
At this point you can add your data flow and setup your import just like you would with a normal file (note your default value for your file name parameter should be to an actual file with the structure you will want to import).
After your data flow drop in your Execute SQL task and set it up how you need. here is an example of direct input and you can see an easy way to reference a parameter is simply a question mark (?).
Next in your sql task setup your parameter mapping by adding in the details you need such as:
Now you are on to your file task. Drop your file task and setup as you desire, but choose your destination and source full path variables to tell the task which file to move.
that's it your are done. there is 1 more thing to note though. The way you have your precedence set in the image you posted you show going from your data flow to your sql and to your file task simultaneously. If your stored procedure relies on your file you may want to put it after your sql task. You can always change the constraint options to "completion" if you want to move the file even if your stored proc fails.
What you want to do is to create a variable in your package, call it something like Filename. In the Edit window of the Foreach you can configure that variable to be set (on the Variable Mappings page- set index to 0).
To create a variable, you will need to have the Variables window showing. Use the View menu to show it if it's not currently open.
Then when calling your stored procedure you can pass the then current value of the variable as a parameter.
This link might help: https://www.simple-talk.com/sql/ssis/ssis-basics-introducing-the-foreach-loop-container/
Problem.
I regularly receive a feed files from different suppliers. Although the column names are consistent the problem comes when some suppliers send text files with more or less columns in there feed file.
Furthermore the arrangement of these files are inconsistent.
Other than the Dynamic data flow task provided by Cozy Roc is there another way I could import these files. I am not a C# guru but i am driven torwards using a "Script Task" control flow or "Script Component" Data flow task.
Any suggestion, samples or direction will greatly be appreciated.
http://www.cozyroc.com/ssis/data-flow-task
Some forums
http://www.sqlservercentral.com/Forums/Topic525799-148-1.aspx#bm526400
http://www.bidn.com/forums/microsoft-business-intelligence/integration-services/26/dynamic-data-flow
Off the top of my head, I have a 50% solution for you.
The problem
SSIS really cares about meta data so variations in it tend to result in exceptions. DTS was far more forgiving in this sense. That strong need for consistent meta data makes use of the Flat File Source troublesome.
Query based solution
If the problem is the component, let's not use it. What I like about this approach is that conceptually, it's the same as querying a table-the order of columns does not matter nor does the presence of extra columns matter.
Variables
I created 3 variables, all of type string: CurrentFileName, InputFolder and Query.
InputFolder is hard wired to the source folder. In my example, it's C:\ssisdata\Kipreal
CurrentFileName is the name of a file. During design time, it was input5columns.csv but that will change at run time.
Query is an expression "SELECT col1, col2, col3, col4, col5 FROM " + #[User::CurrentFilename]
Connection manager
Set up a connection to the input file using the JET OLEDB driver. After creating it as described in the linked article, I renamed it to FileOLEDB and set an expression on the ConnectionManager of "Data Source=" + #[User::InputFolder] + ";Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=\"text;HDR=Yes;FMT=CSVDelimited;\";"
Control Flow
My Control Flow looks like a Data flow task nested in a Foreach file enumerator
Foreach File Enumerator
My Foreach File enumerator is configured to operate on files. I put an expression on the Directory for #[User::InputFolder] Notice that at this point, if the value of that folder needs to change, it'll correctly be updated in both the Connection Manager and the file enumerator. In "Retrieve file name", instead of the default "Fully Qualified", choose "Name and Extension"
In the Variable Mappings tab, assign the value to our #[User::CurrentFileName] variable
At this point, each iteration of the loop will change the value of the #[User::Query to reflect the current file name.
Data Flow
This is actually the easiest piece. Use an OLE DB source and wire it as indicated.
Use the FileOLEDB connection manager and change the Data Access mode to "SQL Command from variable." Use the #[User::Query] variable in there, click OK and you're ready to work.
Sample data
I created two sample files input5columns.csv and input7columns.csv All of the columns of 5 are in 7 but 7 has them in a different order (col2 is ordinal position 2 and 6). I negated all the values in 7 to make it readily apparent which file is being operated on.
col1,col3,col2,col5,col4
1,3,2,5,4
1111,3333,2222,5555,4444
11,33,22,55,44
111,333,222,555,444
and
col1,col3,col7,col5,col4,col6,col2
-1111,-3333,-7777,-5555,-4444,-6666,-2222
-111,-333,-777,-555,-444,-666,-222
-1,-3,-7,-5,-4,-6,-2
-11,-33,-77,-55,-44,-666,-222
Running the package results in these two screen shots
What's missing
I don't know of a way to tell the query based approach that it's OK if a column doesn't exist. If there's a unique key, I suppose you could define your query to have only the columns that must be there and then perform lookups against the file to try and obtain the columns that ought to be there and not fail the lookup if the column doesn't exist. Pretty kludgey though.
Our solution. We use parent child packages. In the parent pacakge we take the individual client files and transform them to our standard format files then call the child package to process the standard import using the file we created. This only works if the client is consistent in what they send though, if they try to change their format from what they agreed to send us, we return the file.
SSIS newbie question:
I have found different usages of a user variable and hence the confusion.
I have defined a user variable customerName.
In some places, (e.g. Script Task Editor's ReadOnlyVariables, it being referred as User::customerName since there is no option to select customerName.
Then in Script Task (Edit script), I see that its being referred as
string custName = Dts.Variables["customerName"].Value.ToString();
and not as
string custName = Dts.Variables["User::customerName"].Value.String();
Where and how does this work? Is there any rule?
Either syntax should be acceptable in a script task. To further complicate matters, you could also reference it as string custName = Dts.Variables[0].Value.ToString();
The User bit refers to the namespace of an SSIS Variable. By default, you can access Variables in the System and User namespace but nothing prevents you from creating variables in a different spaace.
You're also going to run into #[User::customerName] syntax.
How do you check to see if a file does not exist in SQL Server Integration Services 2005?
Is there a native SSIS component which will just do this for you?
I have checked for file existence this using the Script Task and then branch accordingly.
You can do something like
If System.IO.File.Exists("\\Server\Share\Folder\File.Ext") Then
Dts.TaskResult = Dts.Results.Success
Else
Dts.TaskResult = Dts.Results.Failure
End If
Although there are no native components for this, there are several third party components for SSIS that you can use for this purpose.
The File System Task in SSIS is basically for move, copy, delete, etc., but does not support file existence checks.
#Raj More gave a good solution. Another way that I have used before is to create a Foreach Loop Container that loops over the file system for a file spec. If you know the name of the file you want, then you can set the name in a variable and set the spec to equal the variable in the expression tab for the Foreach Loop Container. You could also just specify or a directory or a partial file name if you don't know the exact name but know the naming convention or know there will be no other files in the folder.
If you want to take a specific action based on whether or not there is a file, then you could create a variable with a default value of 0 and create a script task in the Foreach Loop Container that increments the variable. You could also just put the commands in the Foreach Loop Container that you want to execute if you want to execute it for the existence of each individual file. If you want to take an action based on the absence of the file, then you could restrict your precedence constraint after the Foreach Loop Container so that it is restricted on constraint and expression and make it check if the counter variable is > 0.
#Raj's solution could also be used to increment the variable. Instead of using an If Else to raise an error or success result, you could do this:
C#
if (System.IO.File.Exists("\\Server\Share\Folder\File.Ext"))
{ Dts.Variables["my_case_sensitive_variable_name"].Value = Dts.Variables["my_case_sensitive_variable_name"].Value + 1;
}
VB.NET
If System.IO.File.Exists("\\Server\Share\Folder\File.Ext") Then
Dts.Variables["my_case_sensitive_variable_name"].Value = Dts.Variables["my_case_sensitive_variable_name"].Value + 1
End If
The advantage of this approach is that the package may not need to fail in the absence of a file. You could also use a variable name if the file changes that you could define either as a variable in the package or just solely created in the script task. The only short-coming of #Raj's approach is that you have to know the file name you want to check.
Another possibility is to execute a File System Task to rename the file to its existing name or copy the file to its existing location. If the file doesn't exist, then you can route the error to an action. I don't recommend this solution, but I remember using it years ago in one instance where it actually made sense. But in that particular instance, I was actually copying it to a real location.
Good luck!
In Reporting Services I would like to add a parameter that contains data from a custom code block. Ideally, I would be able to run the following code (this is a simple testing example):
Function GetPeriods() As String()
Dim values As System.Collections.ArrayList =
New System.Collections.ArrayList()
For i as integer = 1 to 24
values.Add(i)
Next
Return values.ToArray()
End Function
and put the following in the "Text Field" of the parameter:
=Code.GetPeriods()
However, when I run the report, the parameter I apply this to is disabled and empty. Is there a different technique that should be used? Or am I doing something wrong?
If you're using SQL 2008 Reporting Services then you can have a look at this page which introduces the concept of using custom assemblies.
If you're using SQL 2005 Reporting Services then this link is the one you want.
It's a mostly trivial thing, simply compile your code into a class library and follow the instructions provided to allow your report to reference it.
You are returning an array item (an array of strings) into a text field. Instead, try returning a plain string. That should work. If you would still like to return an array list, you must basically bind it to a list control in your RDL. You can definitely do that with dataset extensions. However, I am not sure if there is any other easy way. Check the proprties of the list control and see if it allows you to directly bind to an array list.
You can create the same stored procedure on SQL Server and load parameter values from that procedure.
To access your members/functions implemented in custom code of SSRS report you should set the access modifier to "Public":
Public Function GetPeriods() As String
...
see article Writing Custom Code in SQL Server Reporting Services
I've been trying to do this same thing, set a simple list of parameter values from report code. None of the links in any of these answers shows how to do this and after quite a bit of digging around I don't think it's even possible. Yes it is possible to get the values from a database query, from a web service, or from a custom assembly, but each of these creates a lot of overhead compared to getting the list from a simple function call like =Code.GetValues(), where the function uses a For loop to create the values.
msvcyc is correct in pointing out that the parameter is expecting a string value, but the function is returning an array. I changed the return type to Array as suggested by prashant sable, but the select list is still grayed out, it does not work. And coldice is correct in saying that the access modifier should be Public.
In my digging around I found an article by James Kovac from 2005 that pointed out why this is not possible. The Parameters class has a get method, but no set method. In the VS 2008 object browser for SSRS 2008 the object name has changed, but it still does not contain a set method (see Microsoft.ReportingServices.Interfaces.IParameter.Name or .Value).
My current workaround is to just hard code the list of values, but if your value list needs to be dynamic then your only choices are database queries, web services, or custom assemblies. I think the easiest workaround of these three is to get the values from the database engine, as suggested by oleksiy.t, as long as you can write a query to return the value list you want. Your list of integers, or my list of time intervals, would both be easy queries to write. Otherwise you will need to use one of the other two workarounds.
I checked your code. The only thing that's wrong is your function returns String(). When I changed your method signature to return Array, it worked fine, in my report.
Change the signature to Function GetPeriods() As Array
Everything I've seen requires parameters and their respective settings to be part of the RDL.
That being said, if you're going to "hardcode" the values, you could create a dataset just for the report, perhaps in XML, or if it needs to be programmatically driven, do it in a web service.