SQL query with variable "Where" - sql

I am new with SQL.
How can I write a query, where the Where condition be dependent on a statement which it will be given from a user?
I have this:
SELECT TablePersdaten.Vorname, TablePersdaten.Nachname, TableBezahlung.Datum, TableBezahlung.BelegNr, TableBezahlung.Betrag, Sum(TableBezahlung.Betrag) AS SummevonBetrag
FROM ((TableTeilnehmer INNER JOIN TablePersdaten ON TableTeilnehmer.IDPersdaten = TablePersdaten.IDPersdaten) INNER JOIN TableKurse ON TableTeilnehmer.IDKurs = TableKurse.IDKurs) INNER JOIN TableBezahlung ON TableTeilnehmer.IDTeilnehmer = TableBezahlung.IDStudent
WHERE TableBezahlung.Datum = "VALUE GIVEN FROM USER"
GROUP BY TablePersdaten.Vorname, TablePersdaten.Nachname, TableBezahlung.Datum, TableBezahlung.BelegNr, TableBezahlung.Betrag
ORDER BY TableBezahlung.Datum;
EDIT: I'm using Access 2013, but I'm coding everything myself with SQL-Code. The values should be given through a form.

Research stored procedures. You can include user input as a parameter and then pass it to a WHERE clause through a declared parameter.
So ideally it would go something like (and beware of the INT part it may have to have a different value that corresponds to table.datum:
CREATE PROCEDURE dbo.Proc1
#parameter1 INT
AS
BEGIN
SELECT TablePersdaten.Vorname, TablePersdaten.Nachname, TableBezahlung.Datum, TableBezahlung.BelegNr, TableBezahlung.Betrag, Sum(TableBezahlung.Betrag) AS SummevonBetrag
FROM ((TableTeilnehmer INNER JOIN TablePersdaten ON TableTeilnehmer.IDPersdaten = TablePersdaten.IDPersdaten) INNER JOIN TableKurse ON TableTeilnehmer.IDKurs = TableKurse.IDKurs) INNER JOIN TableBezahlung ON TableTeilnehmer.IDTeilnehmer = TableBezahlung.IDStudent
WHERE TableBezahlung.Datum = #parameter1
GROUP BY TablePersdaten.Vorname, TablePersdaten.Nachname, TableBezahlung.Datum, TableBezahlung.BelegNr, TableBezahlung.Betrag
ORDER BY TableBezahlung.Datum;
END
And of course execute the procedure after creation:
EXEC dbo.Proc1 '#parameter1value'

If you parameterize the input "VALUE GIVEN FROM USER" that might be what you're after.
...
WHERE TableBezahlung.Datum = &UserValue
...
The single '&' will substitute that value once. If you use '&&', it will substitute that value through the end of your session.

Related

How to make different behavior when 'select all' is selected on a multivalue parameter

I have a reporting services report and a stoproc. The report has a multivalue parameter that is being used like this:
<QueryParameter Name="#Aannemer">
<!-- Joins the multivalue selection into a single comma separated string. -->
<Value>=Join(Parameters!Aannemers.Value,",")</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
The stoproc splits the multivalue parameter using string_split. The stoproc is very long so here is a smaller version of it:
#Aannemer AS NVARCHAR(max) = NULL
[...]
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
WHERE (UI.Uitvoerder IN(select value from string_split(#Aannemer,',')) OR #Aannemer IS NULL )
This all works like a charm so far.
If a user selects 'select all' for the Aannemer parameter, he wants to see all Proefvak's and not filter on Aannemers at all.
But if a Proefvak exists that has no Meetvak connected to it, the Proefvak will never be listed (because the Meetvak holds the Uitvoerder and the Proefvak has no Meetvak). The user still wants to see the Proefvak that has no Meetvak.
Is there a way to check in the stoproc whether the user has selected 'select all', so I can return all Proefvak's?
I hope you understand what I am trying to accomplish. I am a noob when it comes to SQL, so please be clear with the complex parts. Thanks in advance!
==EDIT==
Trying to use #EddiGordo's solution, that looks promising. The next problem is that the #Aannemer parameter does not include the value 'Select All', because this is not a real value. So I tried to edit the code on the SSRS side like this:
<QueryParameter Name="#Aannemer">
<!-- Joins the multivalue selection into a single comma separated string. This paramater should be split up in the stored procedure. -->
<Value>
=IIF(Parameters!Aannemers.Count = COUNT(1, "Aannemers")
, "Select All",
Join(Parameters!Aannemers.Value,","))
</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
But I cannot deploy the SSRS code like this, I get this error:
"The expression used for the parameter '#Aannemer' in the dataset '#Aannemer' includes an aggregate or lookup function. Aggregate and lookup functions cannot be used in query parameter expressions."
Try this:
IF #Aannemer IS NULL
BEGIN
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
END
ELSE
BEGIN
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
WHERE UI.Uitvoerder IN(select value from string_split(#Aannemer,','))
END
try changing :
OR #Aannemer IS NULL
by
OR nullIf(#Aannemer, 'Select All') Is Null
in the where clause of your IN(Select... condition

Using the results of a select sub query as the columns to select in the main query. Injection?

I have a table that contains a column storing sql functions, column names and similar snippets such as below:
ID | Columsql
1 | c.clientname
2 | CONVERT(VARCHAR(10),c.DOB,103)
The reason for this is to use selected rows to dynamically create results from the main query that match spreadsheet templates. EG Template 1 requires the above client name and DOB.
My Subquery is:
select columnsql from CSVColumns cc
left join Templatecolumns ct on cc.id = ct.CSVColumnId
where ct.TemplateId = 1
order by ct.columnposition
The results of this query are 2 rows of text:
c.clientname
CONVERT(VARCHAR(10),c.DOB,103)
I would wish to pass these into my main statement so it would read initially
Select(
select columnsql from CSVColumns cc
left join Templatecolumns ct on cc.id = ct.CSVColumnId
where ct.TemplateId = 1
order by ct.columnposition
) from Clients c
but perform:
select c.clientname, CONVERT(VARCHAR(10),c.DOB,103) from clients c
to present a results set of client names and DOBs.
So far my attempts at 'injecting' are fruitless. Any suggestions?
You can't do this, at least not directly. What you have to do is, in a stored procedure, build up a varchar/string containing a complete SQL statement; you can execute that string.
declare #convCommand varchar(50);
-- some sql to get 'convert(varchar(10), c.DOB, 103) into #convCommand.
declare #fullSql varchar(1000);
#fullSql = 'select c.clientname, ' + #convCommand + ' from c,ients c;';
exec #fullSql
However, that's not the most efficient way to run it - and when you already know what fragment you need to put into it, why don't you just write the statement?
I think the reason you can't do that is that SQL Injection is a dangerous thing. (If you don't know why please do some research!) Having got a dangerous string into a table - e.g 'c.dob from clients c;drop table clients;'- using the column that contains the data to actually execute code would not be a good thing!
EDIT 1:
The original programmer is likely using a C# function:
string newSql = string.format("select c.clientname, {0} from clients c", "convert...");
Basic format is:
string.format("hhh {0} ggg{1}.....{n}, s0, s1,....sn);
{0} in the first string is replaced by the string at s0; {1} is replaces by tge string at s1, .... {n} by the string at sn.
This is probably a reasonable way to do it, though why is needs all the fragments is a bit opaque. You can't duplicate that in sql, save by doing what I suggest above. (SQL doesn't have anything like the same string.format function.)

PLSQL - Select works but Select within Where Clause returns no data

This is driving me crazy. I want to do simple comparison of a column and a variable but it just doesn't work. The QUERY 1 in following code returns me my value when i do a simple select, but i use the resulting variable in my 2nd query it just doesn't work..
It looks sooooo simple but I've been working on this for hours. The complete sql proc is
The big confusing thing is that if I replace v_bbg_symbol with some hard coded 'Value' (like 'FEDL01') it gives a correct answer for Query 2, but when I use the variable v_bbg_symbol it just doesn't work any more
Declare
v_bbg_symbol VARCHAR2(50);
V_OLD_INS_NAME Varchar2(50);
Begin
--QUERY 1
SELECT BBG_SYMBOL into v_bbg_symbol FROM quotes_external WHERE ID = 1;
--Gives output - 'FEDL01'
DBMS_OUTPUT.PUT_LINE('I got here:'||v_bbg_symbol||' is my value');
-QUERY 2
SELECT NAME INTO V_OLD_INS_NAME FROM INSTRUMENT
JOIN CURVE_INSTRUMENT ON
INSTRUMENT.INSTRUMENT_ID = CURVE_INSTRUMENT.INSTRUMENT_ID
JOIN GENERIC_INSTRUMENT ON
CURVE_INSTRUMENT.GENERIC_INSTRUMENT_ID = GENERIC_INSTRUMENT.GENERIC_INSTRUMENT_ID
WHERE CURVE_INSTRUMENT.CURVE_SNAPSHOT_ID =
(SELECT MAX(CURVE_INSTRUMENT.CURVE_SNAPSHOT_ID) FROM CURVE_INSTRUMENT)
AND GENERIC_INSTRUMENT.INSTRUMENT_NAME = v_bbg_symbol;
--ORACLE ERROR 'No Data Found'
DBMS_OUTPUT.PUT_LINE('I got here:'||V_OLD_INS_NAME||' is the new value');
END;
The first 'SELECT' gives me value which i select INTO a variable 'v_bbg_symbol', but when I use the same variable 'v_bbg_symbol' in my 2nd QUERY it pretends as if there is no value passed and does not return any result. If I give static value of 'v_bbg_symbol' i.e. ('FEDL01' in this case) in my 2nd QUERY, the results come as expected.
Please help..
Here is your query, with table aliases to facilitate following it:
SELECT NAME INTO V_OLD_INS_NAME
FROM INSTRUMENT i JOIN
CURVE_INSTRUMENT ci
ON i.INSTRUMENT_ID = ci.INSTRUMENT_ID JOIN
GENERIC_INSTRUMENT gi
ON ci.GENERIC_INSTRUMENT_ID = gi.GENERIC_INSTRUMENT_ID
WHERE ci.CURVE_SNAPSHOT_ID = (SELECT MAX(ci.CURVE_SNAPSHOT_ID) FROM CURVE_INSTRUMENT ci) and
gi.INSTRUMENT_NAME = v_bbg_symbol;
What this says is that the maximum ci.curve_snapshot_id is not for the instrument that is associated with v_bbg_symbol. I think you want a correlated subquery:
SELECT NAME INTO V_OLD_INS_NAME
FROM INSTRUMENT i JOIN
CURVE_INSTRUMENT ci
ON i.INSTRUMENT_ID = ci.INSTRUMENT_ID JOIN
GENERIC_INSTRUMENT gi
ON ci.GENERIC_INSTRUMENT_ID = gi.GENERIC_INSTRUMENT_ID
WHERE ci.CURVE_SNAPSHOT_ID = (SELECT MAX(ci2.CURVE_SNAPSHOT_ID)
FROM CURVE_INSTRUMENT ci2
WHERE ci2.instrument_id = i.instrument_id
) and
gi.INSTRUMENT_NAME = v_bbg_symbol;

How to pass parameter to exists clause?

I have the following method in my model:
def is_user_in_role (security_user_id, role)
SecurityUser.joins(:security_users_roles)
.where(security_users_roles:{role:role})
.exists?("security_users.id=#{security_user_id}")
end
The issue is that the "security_user_id" is not "translated" correctly in the SQL statements. It is always interpreted as "0".
This is a simple output of the generated SQL passing 'Instructor' and '9' as parameters values:
SecurityUser Exists (0.0ms) SELECT 1 AS one FROM security_users INNER JOIN security_users_manage_securities ON security_users_manage_securities.security_user_id = security_users.id INNER JOIN security_users_roles ON security_users_roles.id = security_users_manage_securities.security_users_role_id WHERE security_users_roles.role = 'Instructor' AND security_users.id = 0 FETCH FIRST ROW ONLY
You can see at the end:
security_users.id = 0
Could you tell me how should I transform the exists clause in order to use it with parameter?
I have found it. In order to pass parameters in the exists clause, you should use an array like this:
def is_user_in_role (security_user_id, role)
SecurityUser.joins(:security_users_roles)
.where(security_users_roles:{role:role})
.exists?(["security_users.id=#{security_user_id}"])
end

Assigning a local variable from a table using a join statement

I'm working with SQL, and I can't seem to figure this out for the life of me.
I have a local variable in my stored procedure called #curType. I have two tables, DTXR and DP. DP contains the columns type and programID. DTXR contains the columns programID and QEI. The stored procedure is passed the QEI, and I need to get the type from the table DP and assign it to the local variable #curType.
So, I currently have
select #curType = [Type] From DP d
Join DTXR x on d.ProgramId = x.ProgramID
where x.QEI = #p_QEI.
#p_QEI is the variable passed into the stored procedure.
The problem I'm running in to is this doesn't seem to set #curType. It works if I manually set the program id like this:
select #curType = [Type] from DP Where DP.ProgramId = 120
But the join statement seems to be setting #curType to null.
Actually, this should work. I would check to make sure that the following even returns anything at all (and if it does, what is the first result back?):
select [Type] From DP d
Join DTXR x on d.ProgramId = x.ProgramID
where dtxr.QEI = #p_QEI
That should be the problem, as here is a fiddle proving that a join does nothing different
I'm not sure if your code should works because of WHERE clause. IMO line:
where dtxr.QEI = #p_QEI
should looks like:
where x.QEI = #p_QEI
My second hint, please check #p_QEI variable, does it contain the proper value?