Optional parameters in SQL stored procedure - linq

I am trying to create a stored procedure that has optional parameters. I followed the instructions listed here. I also referenced this SO question. However I keep receiving the following error:
Error converting data type varchar to int.
It works when I execute it as
EXEC sp_get_user {id#}
or
EXEC sp_get_user NULL, {username}
but fails with
EXEC sp_get_user {username}
Stored Procedure
#id int = NULL,
#username nvarchar(50) = NULL
SELECT
username = COALESCE(a.Username, b.Username),
password = COALESCE(a.Password, b.Password),
signup_date = COALESCE(a.SignedUpOn, b.Signup_Date)
FROM table1 a
FULL OUTER JOIN table 2 b
ON a.ID = b.ID
WHERE ((a.ID = #id OR #id IS NULL)
AND (a.Username = #username OR #username IS NULL)
OR (b.ID = #id OR #id IS NULL)
AND (b.Username = #username OR #username IS NULL))
I have tried adding the OPTION(RECOMPILE) and had no success. I want to make this dynamic so other developers can call this SP without having to specify all parameters each time. They will be connecting via LINQ if that makes a difference.

use named parameters in that case
EXEC sp_get_user #username = {username}
if both parameters are optional, SQL server will go by position, so the first one you are passing in will map to the first one in the proc

When executing stored procedures you have to conform for the parameters order as defined respectively, that is why the first and second statements works fine, in the first one EXEC sp_get_user {id#} you passed the id and ignored the user name, then it takes the defined default value. Moreover, in your second statement EXEC sp_get_user NULL, {username} you specified NULL for the id and you passed a value for the username parameter that is why it also works.
On the other hand, the third one EXEC sp_get_user {username} doesn't work because SQL Server treated your parameter {username} as the id value that is why it tries to convert it to integer and of course it will fail. Instead, you have to specify the paramer name while you are passing its value, see the following code:
EXEC sp_get_user #username = {username}

Well, yes, obviously your last attempt will fail.
Your stored proc expects two parameters, in that order:
#id INT
#username NVARCHAR(50)
If you just simply call your stored procedure with a single parameter, then that parameter will be mapped to #id - and thus it needs to be an INT.
If you want to call your stored proc with just a single value for user name, you will need to used a named parameter - you cannot rely on the position (since the first and only parameter will always match to #id)
EXEC sp_get_user #username = {username}

Related

Query Tag is not setting through task in snowflake

We have a stored procedure which alter session and set query_tag parameter to some value. When this procedure is called directly through call statement the query tag is setting, whereas when this procedure is called through task, the query tag is not setting. Please suggest.
CREATE OR REPLACE TASK mytask
WAREHOUSE = COMPUTE_WH
SCHEDULE = '1 minute'
AS CALL dummy();
create or replace procedure dummy()
RETURNS VARCHAR(50)
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
as $$
snowflake.execute( {sqlText: "ALTER SESSION SET QUERY_TAG = 'execute_dummy_proc'" } );
var sql_command = "INSERT INTO mytable(ts) VALUES(CURRENT_TIMESTAMP())";
snowflake.execute ({sqlText: sql_command});
$$;
I reused the provided code. Just changed the second query in your task for a basic select to make it more simple.
CREATE OR REPLACE TASK mytask
WAREHOUSE = COMPUTE_WH
SCHEDULE = '1 minute'
AS CALL dummy();
create or replace procedure dummy()
RETURNS VARCHAR(50)
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
as $$
snowflake.execute( {sqlText: "ALTER SESSION SET QUERY_TAG = 'execute_dummy_proc'" } );
var sql_command = "SELECT 1";
snowflake.execute ({sqlText: sql_command});
$$;
As you can see in screenshot below, there is two consecutive runs of the task and every time the secund query (SELECT 1) is effectively tagged.
In Snowflake each task executes in a new session so query tag only appear after the alter session.
I see nothing wrong here. Just in case you have the possibility to set your variable session in TASK creation.
For exemple
CREATE OR REPLACE TASK mytask
WAREHOUSE = COMPUTE_WH
SCHEDULE = '1 minute'
QUERY_TAG = 'mytag'
AS CALL dummy();
the queries run by certain role cannot be viewed in history using another role lower in hierarchy. To fix this, we gave below grant on the warehouse being used by task: GRANT MONITOR ON WAREHOUSE CUSTOM_WH TO ROLE "DEVELOPER ROLE";
After this, we were able to see queries ran by task and getting the query tag set.

Sqlite3 value in Ruby Script not working as string

I am trying to create a user-auth system and have run into a problem. In this code, I am trying to check if a certain value matches another value in the same row. It prints but does not work as a string when I set it equal to another string.
db.execute("CREATE TABLE IF NOT EXISTS auth(id int, name text, password text)")
db.execute("INSERT INTO auth(id, name, password) VALUES(?, ?, ?)", [1, 'Bugs', 'Carrots'])
t = db.execute("SELECT password FROM auth WHERE name = 'Bugs'")
if t == 'Carrots'
puts "yes"
end
#i am trying to print yes to the console
I think you're getting back an array representing the list of matches, although in this case there's only one row returned. Furthermore, the row itself is an array of values, although in this case the row will be an array of only one value. So you should be comparing t[0][0] rather than just t
You could use the function db.get_first_value instead to simplify this.
(This assumes that name is unique; you probably want to use a UNIQUE constraint in the database schema for both id and name.)
(And, yes, you should take #tadman's warning to heart.)
So here's a minimally altered version of the code you posted above (without the suggested improvements) that gives the desired result:
#!/usr/bin/env ruby
require 'sqlite3'
db = SQLite3::Database.new(':memory:')
db.execute("CREATE TABLE IF NOT EXISTS auth(id int, name text, password text)")
db.execute("INSERT INTO auth(id, name, password) VALUES(?, ?, ?)",
[1, 'Bugs', 'Carrots'])
t = db.execute("SELECT password FROM auth WHERE name = 'Bugs'")
if t[0][0] == 'Carrots'
puts "yes"
end

Visual Studio 2013 TableAdapter Config Wizard for Oracle

I'm a new user to setting up a query using the TableAdapter Config Wizard. I'm trying to run a simple query, and I thought it should look like this:
select id, name, val
from tableA
where name = #parm1 and val = #parm2
This does not work. How do I write the query and pass parameters using Oracle?
In Oracle, your parameters need to be prefixed with a colon, not an at sign:
select id, name, val
from tableA
where name = :parm1 and val = :parm2
On a related note, when you instantiate the parameters, unlike Sybase/SQL Server, you actually leave the identifier off of the parameter name:
OracleCommand cmd = new OracleCommand(sql, connection);
cmd.Parameters.Add(new OracleParameter("parm1", OracleDataType.Varchar));
I may have the Data Type enum slightly off, but you get the idea.

writing basic Ruby code to register user in SQLite database

I need some help writing basic Ruby code to register a user in a SQLite database. I'm very new to Ruby, I checked lots of good examples online but my code still doesn't work.
This is my 1st test project using Ruby, so appreciate any help and apologise for making any bad mistakes.
require 'sqlite3'
def register_user(l)
user = l[1]
pass = l[2]
db = SQLite3::Database.new "database.db"
db.execute("INSERT INTO users (user, pass)
VALUES (#{user}, #{pass})")
end
def cmd_register(l)
if register_user(#{#nick}, l[1])
sv_send 'NOTICE', 'REGISTER', ':*** User created'
else
sv_send 'NOTICE', 'REGISTER', ':*** User not created'
end
end
There are a few problems with your code. First, here:
db.execute("INSERT INTO users (user, pass)
VALUES (#{user}, #{pass})")
You're trying to generate a query that looks like this (supposing the variable user contains "Jordan" and pass contains "xyz"):
INSERT INTO users (user, pass) VALUES('Jordan', 'xyz')
...but your code generates a query that looks like this:
INSERT INTO users (user, pass) VALUES(Jordan, xyz)
Do you see the difference? Values in SQL queries need to be surrounded by quotation marks. Your query will fail because SQLite doesn't know what Jordan is; it only knows what 'Jordan' is.
You could just add quotation marks to your query, but then you would have another problem: SQL injection attacks. Because you're just blindly putting the values of user and pass into your query, an attacker could manipulate those values to perform a different query than you intended. Never use string interpolation (#{var}) or concatenation (+ or <<) when creating an SQL query. (For a brief description of how SQL injection attacks work, read the "How to get hacked" section on this page: http://ruby.bastardsbook.com/chapters/sql/.)
The correct way to use variables in a query is with prepared statements and parameter binding. It looks like this:
statement = db.prepare("INSERT INTO users (user, pass) VALUES (?, ?)")
statement.bind_params(user, pass)
result = statement.execute
What this does is automatically escapes the values of user and pass to make sure they don't do anything you don't expect, wraps them in quotation marks, and substitutes them for the question marks in the query. Another way to do the same thing is this:
result = db.execute("INSERT INTO users (user, pass) VALUES (?, ?)", user, pass)
The other obvious problem with your code is this:
if register_user(#{#nick}, l[1])
This is a syntax error. You can only use the #{var} syntax in a string, like "hello #{var}". In this case you just want to do this:
if register_user(#nick, l[1])
require "sqlite3"
my_db = SQLite3::Database.new "my_db1.db"
my_db.execute <<END_OF_CREATE #The <<END_OF_CREATE .... END_OF_CREATE thing is called HEREDOC syntax, which is one way to create a String that spans multiple lines
CREATE TABLE IF NOT EXISTS users( #A useful SQL command to be aware of.
name varchar(30),
password varchar(30)
);
END_OF_CREATE
def register_user(target_db, user_info)
user_name, user_pass = user_info #A neat trick for "unpacking" an Array
target_db.execute(
"INSERT INTO users (name, password)
VALUES (?, ?)", user_name, user_pass #For security reasons, inserts into a db should use this "question mark" format.
)
end
register_user(my_db, ['John', 'abc123'])
register_user(my_db, ['Jane', 'xyz456'])
my_db.execute("SELECT * FROM users") do |row|
p row #Use the 'p' method instead of puts to print an Array or Hash.
end
--output:--
["John", "abc123"]
["Jane", "xyz456"]
Also, don't ever name a variable l. You absolutely, no exceptions, have to use descriptive variable names. See the code above for an example.
Even though the code above unpacks the user_info array into separate variables, that is actually not required because execute() will take an
Array as an argument:
target_db.execute(
"INSERT INTO users (name, password)
VALUES (?, ?)", user_info
)
In other words, all the values for the question marks can be gathered into an Array and provided as the last argument for execute().
One problem you can run into when writing and testing database programs is when you change one of the column names in your table. The code above will cause an error: the table will not be re-created because the table already exists, but your new code will use the new column name, which won't exist in the table.
So, you might consider using this combination of sql statements:
my_db.execute <<END_OF_DROP
DROP TABLE IF EXISTS users
END_OF_DROP
my_db.execute <<END_OF_CREATE
CREATE TABLE users(
name varchar(30),
password varchar(30)
);
END_OF_CREATE
With those sql statements, if you change one of the column names (or add a column), then your new code won't throw an error because the table is destroyed and recreated with the new column names every time you run your program.

Oracle db gives ORA-01722 for seemingly NO REASON AT ALL

I'm trying to use an Oracle database with ado.net, and it is proving a painful experience. I use Oracle Client (Oracle.Data namespaces).
The following query runs fine from a query window:
UPDATE PRINT_ARGUMENT
SET VALUE = 'Started'
WHERE REQUEST_ID = 1 AND KEYWORD = '{7D066C95-D4D8-441b-AC26-0F4C292A2BE3}'
When I create an OracleCommand however the same thing blows up with ORA-01722. I can't figure out why.
var cmd = cnx.CreateCommand();
cmd.CommandText = #"
UPDATE PRINT_ARGUMENT
SET VALUE = :value
WHERE REQUEST_ID = :requestID AND KEYWORD = :key";
cmd.Parameters.Add(new OracleParameter("requestID", (long)1);
cmd.Parameters.Add(new OracleParameter("key", "{7D066C95-D4D8-441b-AC26-0F4C292A2BE3}");
cmd.Parameters.Add(new OracleParameter("value", "Started");
cnx.Open();
try { int affected = cnx.ExecuteNonQuery(); }
finally { cnx.Close(); }
When I inspect the command in the debugger, the parameters appear to have mapped to the correct types: requestID has OracleDbType.Int64, key and value are both OracleDbType.Varchar2. The values of the parameters are also correct.
This gets even stranger when you consider that I have other queries that operate on the exact same columns (requestID, keyword, value) using the same approach - and they work without a hiccup.
For the record, the column types are requestID NUMBER(10,0); key VARCHAR2(30); value VARCHAR2(2000).
According to Oracle, ORA-01722 'invalid number' means a string failed to convert to a number. Neither of my string values are numbers, neither of the OracleParameters created for them are numeric, and neither
By default, ODP.NET binds parameters by position, not by name, even if they have actual names in the SQL (instead of just ?). So, you are actually binding requestID to :value, key to :requestID and value to :key.
Correct the order of cmd.Parameters.Add in your code, or use BindByName to tell ODP.NET to use the parameter names.
Since you are using named parameters, you have to tell the Oracle client about it. Otherwise your parameters are mixed up (key is assigned to :value):
OracleParameter parameter = new OracleParameter("requestID", (long)1);
parameter.BindByName = true;
cmd.Parameters.Add(parameter);
It's a strange and unexpected behavior, but that's how it is.

Resources