I have SQL that looks like this, which works fine in SSMS:
DECLARE #pPart VARCHAR(100) = '00039',
#pColor VARCHAR(100) = '01816'
SET #pPart = ISNULL(#pPart,'-1')
SET #pColor = ISNULL(#pColor,'-1')
SELECT *
FROM myTable
WHERE (PartID IN (SELECT (#pPart)) OR #pPart = '-1')
AND (ColorID IN (SELECT (#pColor)) OR #pColor = '-1')
If I change either value (or both values) in the DECLARE from a value to NULL, the code returns the results I expect. I'm just not sure how to make this work within Power Query. If both cells are populated with values, the query works. If I delete the value from either cell, it's just returning a list of all the tables in my database (weird...).
I created a named range called "GetValues" that covers B2:B3 and looks like this:
Name
Value
Part
00039
Color
01816
In the Advanced Editor of Power Query, my query looks like this:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
pColor = Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SET #pPart = ISNULL(#pPart,'-1')
SET #pColor = ISNULL(#pColor,'-1')
SELECT *
FROM myTable
WHERE (PartID IN (SELECT (#pPart)) OR #pPart = '-1')
AND (ColorID IN (SELECT (#pColor)) OR #pColor = '-1')
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
I tried changing my SET lines, which also works in SSMS if I change a value to '' or ' ' but still returns a list of all tables in my DB in Power Query. I'm trimming the strings in case the user put a space in the cells instead of leaving them blank:
IF LTRIM(RTRIM(#pPart)) = '' SET #pPart = '-1'
IF LTRIM(RTRIM(#pColor)) = '' SET #pColor = '-1'
So how do I pass a blank cell as NULL or at least as '' ?
EDIT: I also tried stripping my query down to the bare bones to see what parameters are being passed. This query successfully returns the value in B2.
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"'
SELECT #pPart
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
Now I want to see what happens when I include the blank cell B3:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
pColor = Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SELECT #pPart, #pColor
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
This query also returned a list of all the tables in my database.
I also tried changing
in
Target
to
in
pColor
and the query preview shows null in all lowercase, which makes me think it's indeed returning a null value. I just can't figure out how to make this work.
If the goal is to treat blank cell values as a wildcard then this will work: first remove the SET statements then use this sql:
SELECT *
FROM myTable
WHERE (PartID = #pPart OR #pPart is null OR TRIM(#pPart) ='')
AND (ColorID = #pColor OR #pColor is null OR TRIM(#pColor) ='')
You would get:
Alll rows only if both variables are blank.
No rows if #pPart is not null/blank and has no matches
No rows if #pColor is not null/blank and has no matches
You could add this condition to prevent returning any rows when both inputs are blank/ null:
AND ( ISNULL(TRIM(pPart), '') <> '' OR ISNULL(TRIM(pColor), '') <> '')
To get this to work, I had to address the null values before the query started. For whatever reason (EDIT: Jeroen gives the actual reason in the comment below), passing pPart or pColor as NULL would just return a list of tables and didn't actually pass the NULL value. Here's what seems to be working:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = if Source{1}[Column1] = null then "-1" else Source{1}[Column1],
pColor = if Source{2}[Column1] = null then "-1" else Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SELECT *
FROM myTable
WHERE (PartID= '" & pPart & "' OR " & pPart & " = '-1')
AND (ColorID = '" & pColor & "' OR " & pColor & " = '-1')
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
Related
I have database in MS Access 2016, and want to run update query thru Excel VBA - this works. After this I want to return details of updated row (values from two columns - ID, Col1). Now I have only number of affected rows. How to achive this?
My query:
UPDATE
(SELECT TOP 1 ID, Col1, Update_time, Update_user
FROM Table1
WHERE Update_user Is Null
ORDER BY Col2 DESC , ID) AS U_ROW
SET U_ROW.Update_time = Now(), U_ROW.Update_user = [username];
In Excel VBA I run it thru ADODB.Command:
With baseRecordsetCommand
.ActiveConnection = objectConnection
.CommandType = adCmdStoredProc
.CommandText = "qryTest"
.NamedParameters = True
.Parameters.Append .CreateParameter("#username", adVarChar, adParamInput, 255, LCase(Environ("Username")))
.Execute recordsAffected
End With
Usually these kind of ops goes into a stored procedure but in Ms Acces/Excel you have to use VBA. Easiest way is, to retrieve the Id you are about to update before you the update.
So this comes first: save it in a variable
SELECT TOP 1 ID
FROM Table1
WHERE Update_user Is Null
ORDER BY Col2 DESC , ID
And then
update Table1
SET Table1.Update_time = Now(), Table1.Update_user = #username where Id = #idFromFirstQuery;
followed by
select * from Table1 where Id = #idFromFirstQuery;
in this way you know what Id, row you are updating.
OR:
you can turn the now() also into a parameter and supply a timestamp as parameter.
like:
update (table selection )
set update_time = '2020-19-03 10:0=10:10', update_user = 'User1';
after update you can do something like:
Select *
from Table1
where update_user = 'User1' and update_time = '2020-19-03 10:0=10:10';
NOTE!! you are highly assuming the timestamp you are supplying + username is unique. I personally would not use this method.
Not sure on this, but if you have a unique id, you could do something like this. This was done in Access, so the connection would need to be set up, as i believe this is ok.
Function sqlret() As String
Dim c As ADODB.Connection
Dim s As String
Dim r As ADODB.Recordset
Dim l As Long
Set c = CurrentProject.Connection
c.Execute "insert into tblprojects(projecttitle) values ('code1')"
Set r = New ADODB.Recordset
r.Open "select ##identity", c, 1
l = r.Fields(0).Value
r.Close
r.Open "select * from tblprojects where [projectid]=" & l, c, 1
sqlret = r.GetString
End Function
Not able to extract table names used within with clause, I'm using presto-parser version 0.226.
SqlParser sqlParser = new SqlParser();
String sql = "WITH dataset AS ( SELECT ROW('Bob', 38) AS users from tabb ) SELECT * FROM dataset";
Query query = (Query)sqlParser.createStatement(sql, ParsingOptions.builder().build());
QuerySpecification body = (QuerySpecification)query.getQueryBody();
System.out.println("From = " + body.getFrom().get());
/* Output
From = Table{dataset}
*/
Expected output
From = Table{dataset, tabb}
I'm trying to create an update query in Python3/PyQt5.10/Sqlite . A select/insert query made the same way runs fine. Fields & corresponding record exist.
def updateRecords():
theDict = {
"Loc": "PyQt121",
"BoekNr" : "dfdf",
"BoekTitel" : "eeee",
"BoekBedrag" : 999
}
theFilter = " WHERE Loc = 'PyQt'"
query = QSqlQuery()
columns = ', '.join(pDict.keys())
placeholders = ':'+', :'.join(pDict.keys())
sql = 'UPDATE %s SET (%s) VALUES (%s) %s' % (pTable, columns, placeholders, pFilter)
query.prepare(sql)
for key, value in pDict.items():
query.bindValue(":"+key, value)
print (sql)
query.exec_()
print(query.lastError().databaseText())
return query.numRowsAffected()
The sql generated is UPDATE tempbooks SET (Loc, BoekNr, BoekTitel, BoekBedrag) VALUES (:Loc, :BoekNr, :BoekTitel, :BoekBedrag) WHERE Loc = 'PyQt'.
query.lastError().databaseText()) give me "No Query" and updated rows is -1.
The correct syntax for an update query:
UPDATE tablename
set col1 = val1,
col2 = val2,
col3 = val3
WHERE condition
Probably query.prepare(sql) is returning False because of invalid syntax.
I have a problem with string.
I have a variable #Rights which looks like 'ASD,ZXC,QWE,IOP,JKL'
What I need to do is use this string in
SELECT * FROM dbo.Example
WHERE Rights IN (#Rights)
Problem is that I need to convert:
'ASD,ZXC,QWE,IOP,JKL'
to:
'ASD','ZXC','QWE','IOP','JKL'
How can I do this?
you can create a split function
CREATE FUNCTION [dbo].[Split]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
GO
and after you can convert the string in a temp table
DECLARE #Rights NVARCHAR(128)
SET #Rights = 'ASD,ZXC,QWE,IOP,JKL'
SELECT *
INTO #Temp
FROM dbo.Split(#Rights , ',')
and after you can use it in your query like this
SELECT * FROM dbo.Example
WHERE Rights IN (SELECT Data FROM #Temp)
You can try like this:
DECLARE #xml xml, #str varchar(100), #delimiter varchar(10)
SET #str = 'ASD,ZXC,QWE,IOP,JKL'
SET #delimiter = ','
SET #xml = cast(('<X>'+replace(#str, #delimiter, '</X><X>')+'</X>') as xml)
SELECT C.value('.', 'varchar(10)') as value FROM #xml.nodes('X') as X(C)
SQL DEMO
You can use Dynamic SQL:
LiveDemo
-- sample data
CREATE TABLE #Example(ID INT IDENTITY(1,1), Rights VARCHAR(100));
INSERT INTO #Example VALUES ('ASD'), ('ABC'), ('IOP');
DECLARE #Rights NVARCHAR(MAX) = 'ASD,ZXC,QWE,IOP,JKL';
DECLARE #sql NVARCHAR(MAX) =
N'SELECT *
FROM #Example
WHERE Rights IN (''<placeholder>'')';
SET #sql = REPLACE(#sql, '<placeholder>', REPLACE(#Rights, ',', ''','''));
-- SELECT #sql; -- for debug
EXEC dbo.sp_executesql
#sql;
But you should reconsider using Table Valued Parameter instead.
Similar Question may have been asked on this forum regarding exporting stored procedure result to excel file,I've tried few attempts to this but the file does not export to the folder that I expect,Your help is appreciated
Stored Procedure that I created
/****** Object: StoredProcedure [dbo].[Copy_DataDump_SpecificQuery] Script Date: 10/28/2014 15:59:03 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[Copy_DataDump_SpecificQuery]
#SQLScript VARCHAR(MAX)
,#OutPut_Number INT OUTPUT
,#Output_FIleName VARCHAR(MAX) OUTPUT
AS
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN
BEGIN TRY
DECLARE #server Varchar (100)
SET #server = 'MyServerName'
DECLARE #FileName VARCHAR(255)
DECLARE #Date VARCHAR(12)
SELECT #Date = CONVERT(VARCHAR(10),GETDATE(),120)
SET #Output_FIleName = CAST(NEWID() AS VARCHAR(MAX))+ '.xls'
DECLARE #FilePath VARCHAR (4000)
SET #FilePath = '\\ComputerName\Users\MyUserName\Downloads\Exel_File' + #Output_FIleName ;
IF OBJECT_ID('tempDB..##temp_Query', 'U') IS NOT NULL
DROP TABLE ##temp_Query;
----------------------------------------------------------------------------------------------
DECLARE #Query AS VARCHAR(MAX)
DECLARE #FROM_Start INT
SELECT #FROM_Start = CHARINDEX(' FROM ',#SQLScript)
SELECT #Query = SUBSTRING(#SQLScript,0,#FROM_Start) + ' INTO ##temp_Query FROM ' + SUBSTRING(#SQLScript,#FROM_Start+6,LEN(#SQLScript))
PRINT (#Query)
Exec(#Query)
------------------------------------------------------------------------------------------------------------------
DECLARE #dbName VARCHAR (100)
SET #dbName = 'master'
DECLARE #sql VARCHAR (5000)
SET #sql = 'Select * from tempdb.dbo.##temp_Query'
DECLARE #dbName1 VARCHAR (100)
IF OBJECT_ID ('tempDB..##TempExport_Query1','U') is not null
DROP TABLE ##TempExport_Query1
IF OBJECT_ID ('tempDB..##TempExport_Query2','U') is not null
DROP TABLE ##TempExport_Query2
SELECT #dbName1 = #dbName
SELECT #dbName = 'use ' + #dbName + ';'
DECLARE #columnNames VARCHAR (8000), #columnConvert VARCHAR (8000), #tempSQL VARCHAR (8000)
SELECT
#tempSQL = LEFT(#sql, CHARINDEX('from', #sql) - 1) + ' into ##TempExport_Query1 ' +
SUBSTRING(#sql, CHARINDEX('from', #sql) - 1, LEN(#sql))
EXEC (#dbName + #tempSQL)
--SELECT *
--FROM tempdb.INFORMATION_SCHEMA.Columns
--WHERE table_name = '##TempExport_Query1'
SELECT #columnNames = COALESCE(#columnNames + ',', '') + '"' + column_name + '"',
#columnConvert = COALESCE(#columnConvert + ',', '') + 'convert(nvarchar(4000),'
+ '[' + column_name + ']' + CASE
WHEN data_type IN ('datetime', 'smalldatetime') THEN ',121'
WHEN data_type IN ('numeric', 'decimal') THEN ',128'
WHEN data_type IN ('float', 'real', 'money', 'smallmoney') THEN ',2'
WHEN data_type IN ('datetime', 'smalldatetime') THEN ',120' ELSE ''
END + ') as ' + '[' + column_name + ']'
FROM tempdb.INFORMATION_SCHEMA.Columns
WHERE table_name = '##TempExport_Query1'
-- execute select query to insert data and column names into new temp table
SELECT #sql = 'select ' + #columnNames + 'temp##SortID into ##TempExport_Query2 from (select ' + #columnConvert + ',
''2'' as temp##SortID
from ##TempExport_Query1 union all select ''' + REPLACE(#columnNames, ',', ''', ''') + ''',
''1'') t '
EXEC (#sql)
SET #sql = 'bcp " select * from ##TempExport_Query2 ORDER BY temp##SortID " queryout "' + #FilePath +
'" -U uno -P uno -c -T -S ' + #server
EXEC master..xp_cmdshell #sql
SET #OutPut_Number = 1
END TRY
BEGIN CATCH
--DECLARE #ErrorDescription VARCHAR(1000) = 'ERROR - ' + ERROR_MESSAGE()
-- RAISERROR(#ErrorDescription,16,1)
SET #OutPut_Number = 2
--SET #OutPut_Message = ##ERROR
END CATCH
End
Parameters
DECLARE #OutPut_Number INT;
DECLARE #OutPut_Message VARCHAR(1000);
EXECUTE dbo.Copy_DataDump_SpecificQuery 'SELECT O.ID AS SystemNumber
,'' AS ManualNumber
,O.Date AS InvoiceDate
,OT.ID AS CustomerCode
,OT.Name AS CustomerName
,I.ID AS ItemID
,I.Description AS Item
,OL.UnitQty
,OL.FreeQty
,OL.UnitPrice
,OL.GrossValue
,NetSaleValue
,DueDate = ''
,A.ID AS SalesRepCode
,ItemCostPrice = OL.UnitPrice
FROM TxnOrder O
INNER JOIN TxnOrderLine OL ON O.UID = OL.TxnOrderUID AND O.SiteUID = Ol.TxnOrder_SiteUID
INNER JOIN Outlet OT ON O.OutletUID = OT.UID
INNER JOIN Item I ON OL.ItemUID = I.UID
INNER JOIN Agent A ON O.AgentUID = A.UID
WHERE O.mpt_TypeEnum = 1
AND( O.IsPrinted = 1 OR O.mpt_SalesmodelEnum = 2)
--AND O.Date >= #StartDate AND O.Date <= #EndDate
--AND (#DistributorUID IS NULL OR O.DistributorUID = #DistributorUID)
--AND (#AgentUID IS NULL OR O.AgentUID = #AgentUID)'
,#OutPut_Number OUTPUT
,#OutPut_Message OUTPUT
SELECT #OutPut_Message
After I execute I receive the following Output on the SQL Output window
69111E97-BEDE-4BDE-9EBE-C063DB690E9F.xls
I have created the permission for the folder as per below screenshot
This Problem was resolved ,I Logged in to the server via RDP and I executed the SP as per below and it worked out..
DECLARE #OutPut_Number INT;
DECLARE #OutPut_Message VARCHAR(1000);
EXECUTE dbo.Copy_DataDump_SpecificQuery 'SELECT O.ID AS SystemNumber
,O.Date AS InvoiceDate
,OT.ID AS CustomerCode
,OT.Name AS CustomerName
,I.ID AS ItemID
,I.Description AS Item
,OL.UnitQty
,OL.FreeQty
,OL.UnitPrice
,OL.GrossValue
,NetSaleValue
,A.ID AS SalesRepCode
,ItemCostPrice = OL.UnitPrice
FROM TxnOrder O
INNER JOIN TxnOrderLine OL ON O.UID = OL.TxnOrderUID AND O.SiteUID = Ol.TxnOrder_SiteUID
INNER JOIN Outlet OT ON O.OutletUID = OT.UID
INNER JOIN Item I ON OL.ItemUID = I.UID
INNER JOIN Agent A ON O.AgentUID = A.UID
WHERE O.mpt_TypeEnum = 1
AND( O.IsPrinted = 1 OR O.mpt_SalesmodelEnum = 2)'
,#OutPut_Number OUTPUT
,#OutPut_Message OUTPUT
SELECT #OutPut_Message
AND In My select Query I removed the Following Columns
'' AS ManualNumber
DueDate = ''
AND as Im already have the permission to access the server via RDP,I replaced the following path as follows
SET #FilePath = '\\ComputerName\Users\MyUserName\Downloads\Exel_File' + #Output_FIleName
C:\Users\Pathuma\Downloads\Excel
SET #FilePath = '\C:\Users\MyUsername\Downloads\Excel' + #Output_FIleName