Power Query Assign a string from excel to sql server variable - sql-server

I am using Power query & I would like to assign a comma delimited string from an excel cell to a sql server variable. The power query I have so far is below. My Parameter is in a Excel "Table3" in "Column2" :
let
ProdParameterSource =Excel.CurrentWorkbook(){[Name="Table3"]}[Content]{0}[Column2],
Source = Sql.Database("server", "database", [Query="Declare #Product varchar(max) = "&(ProdParameterSource)&" select #Product"])
in
Source
I see the below error :
The parameters I am using as seen in the excel sheet are below :
How can I fix this error and see my input parameters in the sql server variable ABC as '44,216' (with the inverted comma).

I do not do a lot of power query but I do work in Power BI Desktop version.
First, you need to look at the reference to the SQL.Database() on MSDN.
It is looking for a whole query, either a dynamic string you make up or a call to a stored procedure.
My simple example below, pulls data from the Adventure Works DW 2012 Customer table.
What you are missing is a TSQL statement or multiple TSQL statements. Use the semicolon to combine statements into one batch to be called.
The example below create a variable #x as an integer and returns the value. This is almost like you example above.
You will be prompted for security (trusted credentials) and it will tell you that it is an unencrypted connection.
I did some looking around the NET. This article from Reeves Smith is like my last example but slanted towards power query and excel. Just remember, both products use the same engine.
https://reevessmith.wordpress.com/2014/08/19/power-query-and-stored-procedures-with-parameters/
Again

This will fix it: [Query="Declare #Product varchar(max) = '" & ProdParameterSource & "' select #Product"]).
This will fix it in a safer way, since you will escape any extra single-quotes which could break out of the string value: [Query="Declare #Product varchar(max) = '" & Text.Replace(ProdParameterSource, "'", "''") &"' select #Product"]).
What happened is that Power Query treats the text passed to Query as the entire script, and when you built the script you didn't put the value of ProdParameterSource in quotes, so the script appears to set a varchar value to 44,216 (without quotes). This is an invalid statement.

Related

MS Access + SQL Server front end concatenation problem (#NAME)

When I link an SQL Server table to MS Access, I have an issue with concatenation of the SQL Server table/view columns.
I'm used to be doing this in Access: =[FirstName] & " " & [LastName]
However, when I do this with data linked from SQL Server, I get #NAME in the text field every time.
I tried to create a local dummy table in Access and the concatenation works without issues.
I also tried to type the concatenation in SQL Server format: =[FirstName] + ' ' + [LastName], without success.
My current workaround is to create all concatenations directly in the SQL View definitions, but this is quite limiting and I would like to be able to do concatenations directly in Access.
Is it possible?
This looks like a new bug in Access
I linked to a SQL table and added 2 text boxes to a form one an integer and one text
on the integer one =[field] & "b" works on the text field it fails.
even just =[textfieldname] throws an error
A workaround i found is to add firstname and lastname text boxes and rename them txtfirstname and txtlastname then add a third text box and give the datasource property = [txtfirstname] & " " & [txtlastname]
irritating as this used to work

Pass parameter from Excel to SQL in PowerQuery

I want to set local variables or pass parameters from Excel to SQL. I've found similar questions, but all referred to old versions of Excel and/or the answers showed how to filter or manipulate output from a generic SQL query in the Power Query Editor, rather than pass a parameter or modify the SQL, so that the SQL Server supplies data in the needed form.
I'm building a large Microsoft Excel spreadsheet that depends on ten different SQL queries, all against a common SQL Server database. Excel and SQL Server are installed on my laptop and are current versions (as of 16 Mar 2022). All ten queries share a common date restriction, imposed in the WHERE clauses of the queries. The tables accessed and the form of output are very different, so there is no easy way to combine the ten queries into a single query. The queries contain multiple levels of aggregation (e.g. SUM(...)) so I need to restrict the records accessed prior to aggregation and passing results from the query back to Excel.
As currently written, each query begins by setting two date values in local variables. For example,
DECLARE #BEGIN_DATE AS smalldatetime;
DECLARE #END_DATE AS smalldatetime;
#BEGIN_DATE = CAST('2021-03-01 00:00' AS smalldatetime);
#END_DATE = CAST('2021-03-02 23:59' AS smalldatetime);
Every one of the ten queries includes a line in the WHERE clause similar to
WHERE
PickUpDate BETWEEN #BEGIN_DATE AND #END_DATE
Every query will use the same pair of dates. However, the column filtered (PickUpDate above) changes from one query to the next.
As it is, I have to manually edit each of the ten queries to change the two dates--twenty edits in all. This is time-consuming and error-prone. Ideally, I'd like to set the date range in the spreadsheet, in a pop-up dialog box, or any other convenient way and pass the dates to the SQL queries. Then by selecting Data > Refresh All in Excel, update all my tables at once.
Is this possible, and if so, how does one do it?
The answer from David Browne is generally on-target. But I found some difficulties reading data from an Excel table directly into the SQL, given security restrictions in the latest version of Excel/Power Query. Also, since this was the first time I worked directly in M-code and the advanced editor, it was challenging to fill-in the gaps.
I finally got a nice solution running; here is what worked for me.
First, I stored the parameter values in a two-column table. My table is named "ParameterTable" with column headers named "Parameter_Name" and "Value". The value(s) to pass to SQL Server are stored in the Value column. My table has two rows with row entries labeled "Begin_DateTime" and "End_DateTime".
Secondly I created a callable function named “ftnGetParameter.” Select Data > Get Data > From Other Sources > Blank Query. Then select “Advanced Editor.” Delete any boilerplate added by Excel, and enter and save this function
let theParameter=(TableName,ParameterLabel) =>
let
Source=Excel.CurrentWorkbook(){[Name=TableName]}[Content],
value = Source{[Parameter_Name=ParameterLabel]}[Value]
in
value
in
theParameter
Thirdly, code-up your SQL statement as usual. I was trying to pass dates to SQL, so I initially coded with string literals. Enter the query in the usual way. I used Data > Get Data > From Database > From SQL Server Database. Then pasted in the SQL. The two relevant lines in my query looked like this:
DECLARE #BEGIN_DATE AS SMALLDATETIME='2021-01-01 00:00';
DECLARE #END_DATE AS SMALLDATETIME='2021-12-31 23:59';
You could skip this step, but it allowed me to get complex SQL code entered, formatted, and running before I invoked the function to pass the parameters.
Finally, simply replace the string literals in the SQL with code to call the function. My first few lines of M-code looks like this:
let
Source = Sql.Database("DESKTOP-04P8E8C", "nfbdata",
[Query=
"
DECLARE #BEGIN_DATE AS SMALLDATETIME= '" & ftnGetParameter("ParameterTable","Begin_DateTime") & "';
DECLARE #END_DATE AS SMALLDATETIME='" & ftnGetParameter("ParameterTable","End_DateTime") & "' (… the query continues )
Excel will issue some warnings about running the query and prompt you to edit permissions. Once permission has been granted, the function reads the text from the parameter table and passes it into the SQL.
I found that the function call was not optional. Apparently, importing the code directly into a native call to SQL Server is considered an unacceptable security risk.
Many thanks to Mr. David Browne. His post definitely points in the right direction.
You can reference a table on a sheet from Power Query and integrate values from that table into your other queries. Eg if ParameterTable is a single-row table on some worksheet with a column called "StartDate", something like
let
theDate = Date.From( Record.Field(Table.First(ParameterTable),"StartDate") ),
Source = Sql.Databases("localhost"),
AdventureWorksDW2017 = Source{[Name="AdventureWorksDW2017"]}[Data],
dbo_DimDate = AdventureWorksDW2017{[Schema="dbo",Item="DimDate"]}[Data],
#"Filtered Rows" = Table.SelectRows(dbo_DimDate, each [FullDateAlternateKey] = theDate )
in
#"Filtered Rows"
for M query folding, or
let
theDate = Date.From( Record.Field(Table.First(ParameterTable),"StartDate") ),
sql = "
select *
from dimDate
where FullDateAlternateKey = '" & Text.From(theDate) & "'
",
Source = Sql.Database("localhost", "adventureworksdw2017", [Query=sql])
in
Source
for dynamic SQL.

Python3 pypyodbc SQL Server call stored procedure fails

The Python 3.8.1 code that I am working with makes several calls to stored procedures, gets results, does a simple select statement passing a string -- all successfully, using pypyodbc. My last call has me stumped as it simply fails to produce any results, or fails miserably. The stored procedure updates 1 column in 3 tables based on an OrderID, and inserts 1 row in another table. Using SSMS, the call would look like this:
exec GK_set_order '123456'
where 123456 is the OrderID. OrderID is a varchar(). I have logged into SSMS as the user in my Python connect statement and executed that stored procedure and it works every time.
In Python, the order number is used throughout as ADCOrderID, a string. My suspicion is that the single quotes are what is biting me. My first attempt was to create a separate string and execute that string.
exec_SP = "exec GK_set_order '" + ADCOrderID + "'"
cur.execute(exec_SP)
A print(exec_SP) statement shows that it is exactly what I want. But I get no errors, no exceptions, and nothing is updated in the database. I've tried 20 different variations, including double and triple quotes. Nothing was effective.
Changed to:
exec_SP = "exec GK_set_Order(?)"
cur.execute(exec_SP, ADCOrderID)
Now I get an error:
TypeError: Params must be in a list, tuple, or Row
What am I fundamentally missing?

How to avoid errors when multiple Users Increment number field in SQL Server

I am using SQL Server Express 2016 and Excel VBA to generate unique lot numbers for a bunch of different excel documents. Currently, I am creating a new row,then a script in SQL Server increments the lot number. Then I run a select statement to grab the the field from the row that was just created. So far I have not had any issues, however, I am concerned that if the excel file is fired by different users at the same time, the select query for one user may grab the row that another user created. Is this a concern? If so how do I avoid it?
statement = "INSERT INTO LotInfo(RefNum,DateCreated,UserName)VALUES('" & RefNum
& "','" & DateCreated & "','" & user & "')"
conn.Execute statement
Set lot = conn.Execute("SELECT top 1 Lot FROM LotInfo Order By ID desc;")
I don't believe that Scope identity will work.
The statements are entirely separate. first you do the insert. That ends. Then you send the select. While I'm not 100% familiar with VBA, I'm not sure that the second select will know anything about the result of the first invoice.
I would suggest you create a stored procedure which you can call from VBA.
The procedure would perform the insert and then return the lot number.

Using Parameters in MS Reporting Services (SQL Server 2008) against an ODBC data source

I writing a report in Visual Studio that takes a user input parameter and runs against an ODBC datasource. I would like to write the query manually and have reporting services replace part of the where clause with the parameter value before sending it to the database. What seems to be happening is that the #parmName I am assuming will be replaced is actually being sent as part of the SQL statement. Am I missing a configuration setting somewhere or is this simply not possible?
I am not using the filter option in the tool because this appears to bring back the full dataset from the database and do the filtering on the SQL Server.
It sounds like you'll need to treat the SQL Statement as an expression. For example:
="Select col1, col2 from table 1 Where col3 = " & Parameters!Param1.Value
If the where clause is a string you would need to do the following:
="Select col1, col2 from table 1 Where col3 = '" & Parameters!Param1.Value & "'"
Important: Do not use line breaks in your SQL expression. If you do you will get an error.
Holla back if you need any more assistance.
Doesn't ODBC use the old "?" syntax for parameters? Try this:
select col1, col2 from table1 where col3 = ?
The order of your parameters becomes important then, but it's less vulnerable to SQL injection than simply appending the parameter value.
Encountered same problem trying to query an access database via ODBC.
My original query: SELECT A.1 FROM A WHERE A.1 = #parameter resulted in error. Altered to: SELECT A.1 FROM A WHERE A.1 = ?.
You then have to map the query parameter with your report parameter.
I am a bit confused about this question, if you are looking for simple parameter usage then the notation is :*paramName* , however if you want to structurally change the WHERE clause (as you might in sql+ using ?) then you should really be using custom code within the report to define a function that returns the required sql for the query.
Unfortunately, when using custom code, parameters cannot be referenced directly in the generated query but have to have there values concatenated into the resultant String, thus introducing the potential for SQL injection.

Resources