SQL Execution error while running parameter query - vb.net

Can somebody tell me what i have done wrong in my Parameter query as it does not work?
Basically my intention is to create a search result and display it using DataGridView.
These errors appear when I click 'Execute Query' on query builder window.
Below is the SQL Statement
SELECT Products.[Product Name], Products.[Product code], [Brands For Sales].[Brand Name], [Main Group].[Group Name], Category.[Catogory Name], SubCatogory.[SubCatogory Name]
FROM (((((Products INNER JOIN
Category ON Products.[Category-ID] = Category.ID)
INNER JOIN
[Brands For Sales] ON Products.[Brand Name] = [Brands For Sales].ID) INNER JOIN
[Main Group] ON Products.[Group-ID] = [Main Group].ID AND Category.[Group-ID] = [Main Group].ID) INNER JOIN
Category Category_1 ON Products.[Category-ID] = Category_1.ID AND [Main Group].ID = Category_1.[Group-ID]) INNER JOIN
SubCatogory ON Products.[SubCategory-ID] = SubCatogory.ID AND Category.ID = SubCatogory.[Catogory-ID] AND Category_1.ID = SubCatogory.[Catogory-ID])
WHERE (Products.[Product Name] LIKE '%' + #Searchbox + '%')

If I remember correctly, Query Builder doesn't support named parameters even for SQL Server, never mind Access. Replace each of your #ParameterName placeholders with ? and you should be good to go.
EDIT:
The only thing that changes when using positional parameters rather than named parameters (other then the fact that you must add them in the same order as they appear in the SQL, which you should do anyway) is that you cannot reuse a parameter. That means that you might have to pass the same value twice. For instance, if you used this SQL with named parameters:
SELECT *
FROM MyTable
WHERE Column1 = #SomeValue
OR Column2 = #SomeValue
and then you passed a single value to a single parameter to be used twice in the SQL code, you would change the SQL to this with positional parameters:
SELECT *
FROM MyTable
WHERE Column1 = ?
OR Column2 = ?
and then your command would have two parameters and you would pass the same value to both of them. That's exactly what everyone already does with Access even if they do name their parameters, because the Jet and ACE OLE DB providers ignore those names and use positions anyway.

Related

How to write an Open SQL statement with substring in the JOIN ON condition? [duplicate]

I have the following select statement in ABAP:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
INTO corresponding fields of table GT_INSTMUNIC_F
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN EVER AS EV on
MUNIC~POD = EV~VREFER(9).
"where EV~BSTATUS = '14' or EV~BSTATUS = '32'.
My problem with the above statement is that does not recognize the substring/offset operation on the 'ON' clause. If i remove the '(9) then
it recognizes the field, otherwise it gives error:
Field ev~refer is unknown. It is neither in one of the specified tables
nor defined by a "DATA" statement. I have also tried doing something similar in the 'Where' clause, receiving a similar error:
LOOP AT gt_instmunic.
clear wa_gt_instmunic_f.
wa_gt_instmunic_f-mandt = gt_instmunic-mandt.
wa_gt_instmunic_f-bis = gt_instmunic-bis.
wa_gt_instmunic_f-ab = gt_instmunic-ab.
wa_gt_instmunic_f-zzelecdate = gt_instmunic-zzelecdate.
wa_gt_instmunic_f-ZZCERTDATE = gt_instmunic-ZZCERTDATE.
wa_gt_instmunic_f-CONSYEAR = gt_instmunic-CONSYEAR.
wa_gt_instmunic_f-ZDIMO = gt_instmunic-ZDIMO.
wa_gt_instmunic_f-ZZONE_M = gt_instmunic-ZZONE_M.
wa_gt_instmunic_f-ZZONE_T = gt_instmunic-ZZONE_T.
wa_gt_instmunic_f-USAGE_M = gt_instmunic-USAGE_M.
wa_gt_instmunic_f-USAGE_T = gt_instmunic-USAGE_T.
temp_pod = gt_instmunic-pod.
SELECT vrefer
FROM ever
INTO wa_gt_instmunic_f-vrefer
WHERE ( vrefer(9) LIKE temp_pod ). " PROBLEM WITH SUBSTRING
"AND ( BSTATUS = '14' OR BSTATUS = '32' ).
ENDSELECT.
WRITE: / sy-dbcnt.
WRITE: / 'wa is: ', wa_gt_instmunic_f.
WRITE: / 'wa-ever is: ', wa_gt_instmunic_f-vrefer.
APPEND wa_gt_instmunic_f TO gt_instmunic_f.
WRITE: / wa_gt_instmunic_f-vrefer.
ENDLOOP.
itab_size = lines( gt_instmunic_f ).
WRITE: / 'Internal table populated with', itab_size, ' lines'.
The basic task i want to implement is to modify a specific field on one table,
pulling values from another. They have a common field ( pod = vrefer(9) ). Thanks in advance for your time.
If you are on a late enough NetWeaver version, it works on 7.51, you can use the OpenSQL function LEFT or SUBSTRING. Your query would look something like:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN ever AS ev
ON MUNIC~POD EQ LEFT( EV~VREFER, 9 )
INTO corresponding fields of table GT_INSTMUNIC_F.
Note that the INTO clause needs to move to the end of the command as well.
field(9) is a subset operation that is processed by the ABAP environment and can not be translated into a database-level SQL statement (at least not at the moment, but I'd be surprised if it ever will be). Your best bet is either to select the datasets separately and merge them manually (if both are approximately equally large) or pre-select one and use a FAE/IN clause.
They have a common field ( pod = vrefer(9) )
This is a wrong assumption, because they both are not fields, but a field an other thing.
If you really need to do that task through SQL, I'll suggest you to check native SQL sentences like SUBSTRING and check if you can manage to use them within an EXEC_SQL or (better) the CL_SQL* classes.

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.)

Conversion failed when converting the nvarchar value 'CIS100 ' to data type int

Can somebody help me? I'm trying to run a count command so it counts all of the students that are in each class number so I'm running this command. Although I'm getting this error.
Conversion failed when converting the nvarchar value 'CIS100 ' to data type int
Here's my SQL Query
USE RMUDB
GO
SELECt *
FROM Class
WHERE [Class Number] = (Select Count([Class Number]) FROM Enrollment)
If you want to count the students in each class, doesn't the following query do what you want?
SELECT c.[Class Number], COUNT(e.[Class Number])
FROM Class c LEFT JOIN
Enrollment e
ON c.[Class Number] = e.[Class Number]
GROUP BY c.[Class Number];
Your query is comparing the result of a counting operation (an integer) to [Class Number], which is the name of something. It is unlikely that = makes sense.

SQL query with variable "Where"

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.