Replace SQL query parameter in a Excel power query - excel

I have a workbook where I fetch data from SQL Server using fixed parameter values for a SQL query.
I want to make another sheet and have the parameter for the SQL query be taken from the cell values.
I didn't find anything on this regard.
Also I would like to refresh the data as soon as the cell values changes in the other sheet.

For this to work, you need to set up three different parts:
1) A parameter table in an Excel sheet
2) Changes to the advanced editor in PowerQuery
3) A macro to refresh the PQ when any cells in the parameter table are changed
1) Excel Table
You can see I included a column called param which can hold a Parameter name to help keep straight which parameter is which.
2) PQ Advanced Editor
let
ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Param = "'" & Text.From(ParamTable[value]{0}) & "'",
Source = Sql.Database("IP Address", "Database Name", [Query="Select * from weeks#(lf)where date >= '2018-01-01' and date < " &Param])
in
Source
Equivalent alternative: (Difference in location of variable used in SQL query.)
let
ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Param = "'" & Text.From(ParamTable[value]{0}) & "'",
Source = Sql.Database("IP Address", "Database Name", [Query="Select * from weeks#(lf)where date < " &Param & " and date >= '2018-01-01'"])
in
Source
Alternative Variable Type: (If dealing with numbers, the string markers ' aren't required)
let
ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Param = Text.From(ParamTable[value]{0}),
Source = Sql.Database("IP Address", "Database Name", [Query="Select * from weeks#(lf)where cnt < " &Param & " and date >= '2018-01-01'"])
in
Source
Explanation:
After pulling the Parameter Table into the PQ Query (ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content]), the columns can be accessed by column name [value] and the rows by a zero-index number {0}. Since I was pulling in a date-value. I needed to convert it to a string value I could insert into the SQL Query -- thus the Text.From() and the appended ''s to the ends (SQL marks strings with single ' rather than the double ")
Since I named the variable Param, to use it in the string, I substituted &Param for the value which had originally been there.
2.1 Power Query's Value.NativeQuery
let
ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Param = ParamTable[value]{0},
Source = Value.NativeQuery(Sql.Database("IP Address", "Database Name"), "Select * from weeks where date < #dateSel and date >= '2018-01-01'",[dateSel = Param])
in
Source
Alternative Formatting:
let
ParamTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Param = ParamTable[value]{0},
Source = Sql.Database("IP Address", "Database Name"),
Data = Value.NativeQuery(Source, "
Select * from weeks
where date < #dateSel and date >= '2018-01-01'
",[dateSel = Param])
in
Source
Notes:
When using Value.NativeQuery(), you can pass a date or datetime value directly in as a variable without having to include the single apostrophes.
Sometimes splitting the data retrieval into a Source step and a NativeQuery step can help with PQ's sporadic firewall issues.
3) Macro
This works for a simple check if anything in the table has changed, then runs the refresh. You will need to make sure this is placed in the correct module. Items you will need to change are:
Sheet1 is the codename of the worksheet with the parameter table.
"Table" is the name of the Parameter table
"Query - Query1" is the name of the connection to be refreshed
Note: Query1 is the name of the query. Default names for connections are usually Query - & query name
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Sheet1.ListObjects("Table1").DataBodyRange) Is Nothing Then
ThisWorkbook.Connections("Query - Query1").Refresh
End If
End Sub

Related

Automatically Run Access Query w/ date range parameters

Trying to automatically run an access query in excel and update the date criteria based on user input. Not sure how to code in vba a parameter for entering the between date and getting the query to post automatically in excel under a header column in a2.
Access Query:
'''SELECT hosp_chg.HOSP_ACCT_ID, hosp_chg.SVC_DATE, hosp_chg.POST_DATE, [hosp_chg.POST_DATE]-
[hosp_chg.SVC_DATE] AS [Lag Days], hosp_chg.ACCT_CLASS_ID, acct_class_master.TITLE, "" AS
[Inpatient or Outpatient], hosp_chg.REVENUE_CODE_ID, hosp_chg.COST_CENTER_ID,
cost_center_master.COST_CENTER_CODE, cost_center_master.COST_CENTER_NAME, "" AS [WDY Cost
Center Mapping], hosp_chg.DEPT_ID, department_master.DEPT_NAME, hosp_chg.PROC_ID,
procedure_master.PROC_CODE, procedure_master.PROC_NAME, hosp_chg.ORIG_AMT, hosp_chg.QUANTITY,
hosp_chg.LATE_CHG_YN, user_master.USER_ID, user_master.USER_NAME,
user_master.DEFAULT_USERROLE, "" AS [Include/Exclude in Reporting],
hosp_chg.REVERSE_ORIG_TRAN_ID, hosp_chg.REPOST_ORIG_TRAN_ID,
hosp_chg.LATE_CHG_CRED_ORIG_TRAN_ID, hosp_chg.LATE_CHG_CORRECT_ORIG_TRAN_ID
FROM acct_class_master INNER JOIN ((((hosp_chg INNER JOIN cost_center_master ON
hosp_chg.COST_CENTER_ID = cost_center_master.COST_CENTER_ID) INNER JOIN department_master ON
hosp_chg.DEPT_ID = department_master.DEPT_ID) INNER JOIN procedure_master ON hosp_chg.PROC_ID
= procedure_master.PROC_ID) INNER JOIN user_master ON hosp_chg.USER_ID = user_master.USER_ID)
ON acct_class_master.ID = hosp_chg.ACCT_CLASS_ID
GROUP BY hosp_chg.HOSP_ACCT_ID, hosp_chg.SVC_DATE, hosp_chg.POST_DATE, [hosp_chg.POST_DATE]-
[hosp_chg.SVC_DATE], hosp_chg.ACCT_CLASS_ID, acct_class_master.TITLE,
hosp_chg.REVENUE_CODE_ID, hosp_chg.COST_CENTER_ID, cost_center_master.COST_CENTER_CODE,
cost_center_master.COST_CENTER_NAME, hosp_chg.DEPT_ID, department_master.DEPT_NAME,
hosp_chg.PROC_ID, procedure_master.PROC_CODE, procedure_master.PROC_NAME, hosp_chg.ORIG_AMT,
hosp_chg.QUANTITY, hosp_chg.LATE_CHG_YN, user_master.USER_ID, user_master.USER_NAME,
user_master.DEFAULT_USERROLE, "", hosp_chg.REVERSE_ORIG_TRAN_ID, hosp_chg.REPOST_ORIG_TRAN_ID,
hosp_chg.LATE_CHG_CRED_ORIG_TRAN_ID, hosp_chg.LATE_CHG_CORRECT_ORIG_TRAN_ID, ""
HAVING (((hosp_chg.POST_DATE) Between [Enter the beginning date MM/DD/YY] And [Enter the
ending date MM/DD/YY]) AND ((hosp_chg.ORIG_AMT)>0) AND ((hosp_chg.LATE_CHG_YN)="Y") AND
((hosp_chg.REVERSE_ORIG_TRAN_ID) Is Null) AND ((hosp_chg.REPOST_ORIG_TRAN_ID) Is Null) AND
((hosp_chg.LATE_CHG_CRED_ORIG_TRAN_ID) Is Null) AND ((hosp_chg.LATE_CHG_CORRECT_ORIG_TRAN_ID)
Is Null))
ORDER BY hosp_chg.REVENUE_CODE_ID;'''
'
My error is on the parameters but i do not know how to fix any help would be greatly appreciated. THANKS IN ADVANCE!!
Ricardo A has given you a good answer. Here's the VBA code to do what he suggests:
Have the user enter the beginning and ending dates in two cells of the workbook, perhaps cells X1 and Y1
Use the data from those cells to put the values in the query as follows (assuming your query is a variable named SQL):
SQL = Replace(SQL, "[Enter the beginning date MM/DD/YY]", "#" & range("X1").text & "#")
SQL = Replace(SQL, "[Enter the ending date MM/DD/YY]", "#" & range("Y1").text & "#")
That will put the values into your query as date literals.

Dropdown list with Adodb query

I would like to create the dropdown list with the results from my query. I'm looking for help please because I don't know how to display this results on the list.
The exemple of the list:
My query is :
'DROPDOWN LIST
Private Sub cb_gest_Change()
If Not FSD.cb_gest.MatchFound And FSD.cb_gest <> "" Then
MsgBox "Saisie impossible, le gestionnaire n'existe pas !", , "Contrôle
Gestionnaire"
FSD.cb_gest = ""
Else
FSD.Cells(29, COL_DATA) = FSD.cb_gest
End If
End Sub
'DROPDOWN LIST
Sub init_combo()
Dim Resultat As ADODB.Recordset
Dim Requete As String
FSD.cb_gest.Clear
Requete = "select lb_gestion from DB_GESTIONNAIRE "
Requete = Requete + "WHERE (d_deb_valid <= TRUNC(SYSDATE) OR d_deb_valid IS
NULL) AND (d_fin_valid >= TRUNC(SYSDATE) OR d_fin_valid IS NULL)"
Requete = Requete + " ORDER BY LB_GESTION"
Set Resultat = New ADODB.Recordset
Resultat.ActiveConnection = oBase
Resultat.Source = Requete
Resultat.Open
While Not Resultat.EOF
FSD.cb_gest.AddItem Resultat!lb_gestion
Resultat.MoveNext
Wend
If FSD.Cells(29, COL_DATA).Value <> "" Then
FSD.cb_gest = FSD.Cells(29, COL_DATA).Value
Else
FSD.Cells(29, COL_DATA).Value = ""
End If
End Sub
Thank you for your help !
Consider a different, codeless approach:
Add a new sheet to the host document / workbook
Import the external data from the "Data" Ribbon tab (select "From SQL Server")
Excel creates a ListObject table backed with a QueryTable object that uses a WorkbookConnection that can be configured to automatically refresh on open, or left alone as a one-time pull.
Select the produit column in the ListObject/table; Excel highlights the entire column content and leaves the heading un-selected.
From the "Formulas" Ribbon tab, click the "Define Name" command in the "Defined Names" group.
Name the range ProductsList, verify it refers to TableName[produit] so that it automatically grows and shrinks to fit the column contents.
Change the data validation list to =ProductsList.
Hide the worksheet housing the query and table, if needed.
No code needed, and the validation list will always keep up with the query results as they are refreshed.
Side note, the query appears to be making inefficient cross-joins, and at least one of them is a where-join that can be expressed as an inner join. Are you sure the query is yielding the expected records (I'm suspecting it's yielding a ton of duplicates, depending on how many records exist in the cross-joined tables)?
SELECT prod.cd_produit AS produit
FROM db_dossier sousc, db_produit prod, db_protocole proto, db_tiers tiers, db_personne pers
WHERE sousc.cd_dossier = 'SOUSC' AND sousc.lp_etat_doss NOT IN ('ANNUL','A30','IMPAY') AND sousc.is_produit = prod.is_produit
Instinct would be to remove the tables we're not selecting or filtering anything from - if this query produces the same expected output, then assuming primary and foreign keys are defined I believe its execution plan would be more efficient:
SELECT prod.cd_produit AS produit
FROM db_dossier AS sousc
INNER JOIN db_produit AS prod ON sousc.is_produit = prod.is_produit
WHERE sousc.cd_dossier = 'SOUSC' AND sousc.lp_etat_doss NOT IN ('ANNUL','A30','IMPAY')

Power Query - Get Data from AnalysisServices (Cube) - Filter with User-Function result

I have the following problem. I'm getting Data (Excel 365 - Power Query) from a Cube with "Get Data from Analysis Services". -> Selling Qty an Values for filtered years by week.
Every thing is fine if I use Filter, updatetime ca. 3-4 seconds:
#"Filtered Rows1" = Table.SelectRows(#"Added Items", each
(Cube.AttributeMemberId([#"Date.Year (4-4-5)"]) = "[Date].[Year 4-4-5].&["&
Number.ToText(2019) &"]" meta
[DisplayName = Number.ToText(2019)]
or Cube.AttributeMemberId([#"Date.Year (4-4-5)"]) = "[Date].[Year 4-4-5].&["&
Number.ToText(2020) &"]" meta
[DisplayName = Number.ToText(2020)]
)
Now I like to do that dynamic, so that I can get the years from a cell in excel. I use the following M-Function "fktGetNamedCellValue" for this:
let
Source = (FieldInput as text) =>
let Quelle = Excel.CurrentWorkbook(){[Name=FieldInput]}[Content],
Inhalt = Number.From(Quelle{0}[Column1])
in Inhalt
in Source
I replaced the years in the Filter-Step with the function.
The cells are named "cell_Prev_Year" and "cell_Plan_Year"
The cells in Excel formated as Numbers (and there are only Numbers in it)
The updatetime now -> endless!!!
#"Filtered Rows1" = Table.SelectRows(#"Added Items", each
(Cube.AttributeMemberId([#"Date.Year (4-4-5)"]) = "[Date].[Year 4-4-5].&["&
Number.ToText(fktGetNamedCellValue("cell_Prev_Year") &"]" meta
[DisplayName = Number.ToText(fktGetNamedCellValue("cell_Prev_Year"))]
or Cube.AttributeMemberId([#"Date.Year (4-4-5)"]) = "[Date].[Year 4-4-5].&["&
Number.ToText(fktGetNamedCellValue("cell_Plan_Year")) &"]" meta
[DisplayName = Number.ToText(fktGetNamedCellValue("cell_Plan_Year"))]
)
If I use a "normal" parameter with the value "2019" or "2020" everything is fine.
Only if I use the fktGetNamedCellValue it will not run correctly.
I`ed Trim an Clean the result. Formated it as Text and Number... nothing helped.
I have to use userfriendly Parameter (not set in Power Query) for this, so I hope for some help :)
Best Regards
Chris
(PS: I hope u understand my english)
I solved this problem as follows.
Since it is not an good idea to use an user-function as parameter to get data from an cube. I think this method disables query-folding or is called a lot of times in the process, I decided to use an power-query parameter.
I change this Parameter with vba by checking the worksheet_change event and calling this sub:
Sub refresh_Parameter(ParameterName As String, ParameterValue As Variant)
Dim strOldFormula As String
Dim strParametersMeta As String
strOldFormula = ThisWorkbook.Queries(ParameterName).Formula
strParametersMeta = Mid(strOldFormula, InStr(1, strOldFormula, "meta"), Len(strOldFormula))
ThisWorkbook.Queries(ParameterName).Formula = ParameterValue & " " & strParametersMeta
Debug.Print strOldFormula
Debug.Print strParametersMeta
End Sub
The parameters for the sub arte the PARAMETER Name in PowerQuery and the VALUE which should be set. For this the sub extracts the meta-data from the query-formula and combines it with the new Value.
Maybe someone needs this :)
Best regards chris

Passing string result to query then export as csv

Good Afternoon,
I have an access query that contains a list of all my customers lets call that CUS
I have another query that has a list of ORDERS
I would like to write some VBS that cycles through the customer list and exports a csv file containing all orders that belong to that customer.
The vba would then move on to the next customer on the list and perform the same action.
Any help would be great.
Snippet of code below
almost there cant get the WHERE condition working it keeps displaying a popup for me to populate however the same string is feeding the msgbox fine here is a snippet below tht is within the loop
strcustcode = rs!OCUSTCODE
ordercount = rs!orders
TIMEFILE = Format$(Time, "HHMM")
MsgBox ([strcustcode] & " has " & [ordercount] & " orders")
StrSQL = "Select * From [24-ND_Cus] where [24-ND_Cus].[OCUSTCODE] = strcustcode "
Set qd = db.CreateQueryDef("tmpExport", StrSQL)
DoCmd.TransferText acExportDelim, , "tmpExport", "c:file.csv" db.QueryDefs.Delete "tmpExport" –
Don't use [ ] around VBA variables. Don't use parens for the MsgBox when you just want to give user a message. The parens make it a function that requires a response by user to set a variable.
MsgBox strcustcode & " has " & ordercount & " orders"
Concatenate the variable into the SQL statement. If OCUSTCODE is a text type field, use apostrophe delimiters for the parameter.
StrSQL = "Select * From [24-ND_Cus] Where [OCUSTCODE] = '" & strcustcode & "'"
I don't advise code that routinely modifies design and changing a query SQL statement is changing design. If the only change is filter criteria and a dynamic parameterized query won't work, I suggest a 'temp' table - table is permanent, data is temporary. Delete and write records to the table and export the table.

How do I construct a SELECT statement incorporating Excel cell values?

I am querying an external database with power query through Excel. What I am wanting to do is populate my where clause based off of cell values so for example my sql statement would read something like
Select *
From employees
where hiredate between Sheet1!A1 and Sheet2!A2
I tried the above syntax and it does not work, but I think it illustrates what I am wanting to achieve.
How can I pass parameters from my Excel sheet into my power query syntax?
EDIT
I tried following the blog.oraylis.de (not actual link, link is in comments), but I get the below error when I try to execute my statement
DataSource.Error ODBC:Error[4203] ERROR: column "start_p" does not exist;
I created a table named it parameters added headers & Values, and the full SQL I try to run is this:
let
startp_Param = Excel.CurrentWorkbook(){[Name="Parameter"]}[Content],
startp_Value = startp_Param {0}[Value],
endp_Param = Excel.CurrentWorkbook(){[Name="Parameter"]}[Content],
endp_Value = endp_Param {1}[Value],
Source = Odbc.Query("dsn=postgresql", "Select * FROM employees where hiredate BETWEEN startp_Value AND endp_Value")
in
Source
EDIT # 2
I altered my query to read like this
"Select *
FROM employees
where hiredate BETWEEN " & startp_Value & " AND " & endp_Value
However this now presents an error of:
"We cannot apply operator & to types Text and Number"
startp_Value and endp_Value are steps in Power Query, so you have to use & to add it to the string, like this:
Source = Odbc.Query("dsn=postgresql", "Select * FROM employees where hiredate BETWEEN " & startp_Value & " AND " & endp_Value
This doesn't handle sanitizating your SQL query, so you may want to do it to startp_Value and endp_Value (for example, by converting to a Date and then back to a Text).

Resources