SET vs. SELECT - What's the difference? - performance

Can someone please identify the functional/performance differences, if any, between SET and SELECT in T-SQL? Under what conditions should I choose one over the other?
UPDATE:
Thanks to all who responded. As a few people pointed out, this article by Narayana Vyas Kondreddi has lots of good info. I also perused the net after reading the article and found this condensed version by Ryan Farley which offers the highlights and thought I would share them:
SET is the ANSI standard for
variable assignment, SELECT is not.
SET can only assign one variable at
a time, SELECT can make multiple
assignments at once.
If assigning from a query, SET can
only assign a scalar value. If the
query returns multiple values/rows
then SET will raise an error. SELECT
will assign one of the values to the
variable and hide the fact that
multiple values were returned (so
you'd likely never know why
something was going wrong elsewhere - have fun troubleshooting that one)
When assigning from a query if there
is no value returned then SET will
assign NULL, where SELECT will not
make the assignment at all (so the
variable will not be changed from
it's previous value)
As far as speed differences - there
are no direct differences between
SET and SELECT. However SELECT's
ability to make multiple assignments
in one shot does give it a slight
speed advantage over SET.

SET is the ANSI standard way of assigning values to variables, and SELECT is not. But you can use SELECT to assign values to more than one variable at a time. SET allows you to assign data to only one variable at a time. So that in performance is where SELECT will be a winner.
For more detail and examples refer to: Difference between SET and SELECT when assigning values to variables

SQL Server: one situation where you have to use SELECT is when assigning ##ERROR and ##ROWCOUNT as these have to be set in the same statement (otherwise they get reset):
SELECT #error = ##ERROR, #rowcount = ##ROWCOUNT
(SET only works with one value at a time)

Set is ANSI standard for assigning values to variables.
Select can be used when assigning values to multiple vairables.
For more details please read this detailed post by Narayana Vyas

set and select both assign values to variables. Using select you can assign values to more than one variable
some thing like
select #var1=1,#var2=2
where as using set you have to use separate set statements (its an ANSI way of assigning values) i.e.
set #var1=1
set #var2=2
I hope this helps
cheers

Common question, canned answer:
http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/25/defensive-database-programming-set-vs-select.aspx

Related

Does sql_id change if bind variable values are changed

I have a sql_id. The corresponding SELECT SQL query has 4 bind variables.
There is a program created by me which lets me know that it ran for 1000 times in the last 1 month.
So basically I want to know that all 1000 times the same bind variable was used or not.
For the latest one, I got the bind variable values from v$sql_bind_capture.
So is it that whatever is the latest value in v$sql_bind_capture is the same used all 1000 times?
Does sql_id generation consider the bind value for generation of sql_id or it is the query without the bind value that is used to generate sql_id?
Thanks
Tarun
No, different bind value passed each time will not cause the SQL_ID to change. A different bind value passed may cause the sql plan hash value to change (PHV) but not the SQL_ID.
About your main question:
so basically I want to know that all 1000 times the same bind variable was used or not.
There are 2 standard ways to do that:
add hint "monitor" into the query and check bind variables values in v$sql_monitor. I have own script for that: https://github.com/xtender/xt_scripts/blob/master/rtsm/binds.sql
enable tracing for your sql_id:
alter system set events 'sql_trace [sql:&sqlid] bind=true, wait=false';
&sqlid is substituion variable which you can set to to your needed sql_id. Then you can periodically check bind variables tracefiles, for example using grep.

PreparedStatement - set param to DEFAULT (keyword)

Although this question seems to be close to this one, it is actually different.
Question
Is there any way to specify DEFAULT value as a parameter in JDBC's PreparedStatement?
Use-case
I'd like to have a single statement used for several inserts (or batch) into the table having some column defined as, say:
updated TIMESTAMP NOT NULL DEFAULT TIMESTAMP.
Now, assume that I got a non-uniform set of entries to insert, some of them DO have a value for that column while others DOESN'T (effectively relying on the DB to generate it).
Instead of 'divide and conquer' pattern (which obviously may become exponentially complex if there are more columns like this), I'm looking to run the same PreparedStatement in the single batch, while specifying DEFAULT value for all those entries that DOESN'T have the required values.
Well, seems that a statement of the #a_horse_with_no_name is straight forwardly to the point.
Gone over the PreparedStatement Java 9 docs again and found no hints to anything even close to this.
I'm missing a functionality to set parameters to a DB functions/keywords like DEFAULT, CURRENT_TIMESTAMP etc, but that's the state of PreparedStatement as of now.

Using variables in From part of a task flow source

Is there any way to use a variable in the from part (for example SELECT myColumn1 FROM ?) in a task flow - source without having to give the variable a valid default value first?
To be more exact in my situation it is so that I'm getting the tablenames out of a table and then use a control workflow to foreach over the list of tablenames and then call a workflow from within that then gets data from these tables each. In this workflow I have the before mentioned SELECT statement.
To get it to work properly I had to set the variable to a valid default value (on package level) as else I could not create the workflow itself (as the datasource couldn't be created as the select was invalid without the default value).
So my question here is: Is there any workaround possible in this case where I don't need a valid default value for the variable?
The datatables:
The different tables which are selected in the dataflow have the exact same tables in terms of columns (thus which columns, naming of columns and datatypes of columns). Only the data inside of them is different (thus its data for customer A, customer B,....).
You're in luck as this is a trivial thing to implement with SSIS.
The base problem for most people is that they come at SSIS like it's still DTS where you could do whatever you want inside a data flow. They threw out the extreme flexibility with DTS in favor of raw processing performance.
You cannot parameterize the table in a SQL statement. It's simply not allowed.
Instead, the approach that people take is to use Expressions. In your case, assuming you had two Variables of type String created, #[User::QualifiedTableName] and #[User::QuerySource]
Assume that [dbo].[spt_values] is assigned to QualifiedTableName. As you loop through the table names, you will assign the value into this variable.
The "trick" is to apply an expression to the #[User::QuerySource]. Make the expression
"SELECT T.* FROM " + #[User::QualifiedTableName] + " AS T;"
This allows you to change out your table name whenever the value of the other variable changes.
In your data flow, you will change your OLE DB Source to be driven by a query contained in a variable instead of the traditional table selection.
If you want an example of where I use QuerySource to drive a data flow, there's an example on mixing an integer and string in an ssis derived column
Create a second variable. Set its Expression to create the full
Select statement, using the value of the first variable.
In the Data Source, use "SQL command from variable" option for the
Data Access Mode property.
If you can, set a default value for the variable you created in step
That will make filling out the columns from your data source much easier.
If you can't use a default value for the variable, set the Data
Source's ValidateExternalMetadata property to False.
You may have to open the data source with the Advanced Editor and
create Output columns manually.

Toad for Oracle bind variables with IN clause

I have a query that looks like this:
select * from foo where id in (:ids)
where the id column is a number.
When running this in TOAD version 11.0.0.116, I want to supply a list of ids so that the resulting query is:
select * from foo where id in (1,2,3)
The simple minded approach below gives an error that 1,2,3 is not a valid floating point value. Is there a type/value combination that will let me run the desired query?
CLARIFICATION: the query as shown is how it appears in my code, and I am pasting it into TOAD for testing the results of the query with various values. To date I have simply done a text replacement of the bind variable in TOAD with the comma separated list, and this works fine but is a bit annoying for trying different lists of values. Additionally, I have several queries of this form that I test in this way, so I was looking for a less pedestrian way to enter a list of values in TOAD without modifying the query. If this is not possible, I will continue with the pedestrian approach.
As indicated by OldProgrammer, the Gerrat's answer that "You can't use comma-separated values in one bind variable" in the indicated thread correctly answers this question as well.

Crystal Reports Setting Global Subreport Variable

I am trying to set a couple of global variables in a subreport so that it pulls and stores the data I need in each.
Say I go into the formula workshop and create a new formula. Right now I have
Global numbervar name:= ;
I have a single table with multiple fields. I have one field named {table.order} and another named {table.amount}. Both of these are numbers. How do I assign to this variable the amount in the associated amount field when the order is -1? I'm really not familiar with crystal syntax at all.
After this, where would I need to drag and drop this formula in the report to pick up this data or is simply creating the formula in the formula explorer enough? If it needs to be physically dragged into the report, will anything show up or will I need to suppress it so it is not visible and if that is the case, will it still work suppressed?
Thanks for any help you can give.
Are you trying to pass the value in this variable back to the main report? If so, you'll need to make this a Shared Numbervar, not a Global Numbervar.
To answer your question; create this formula:
global numbervar name;
if {table.order} = -1 then name := {table.amount}
...and drop it into your subreport's details section. Note that any formulas, summaries, running totals, SQL expressions, etc. that you create but are not placed in the actual report won't be run. However, after placing it in the report, it will display. To prevent this, right click on the field, go to the 'Common' tab, and then check 'Suppress'. The formula will still work when suppressed.
One other thing to keep in mind is that if your subreport(s) contain more than one row of data, the variable will be overwritten for each.

Resources