SQL Local Variables - sql

I was writing a SQL script and suddenly got confused at the following line:
IF EXISTS(SELECT #IDTTIC = IDTTIC TOP 1 * FROM #ProblemTickets)
where #ProblemTickets is my table variable.
Is the above condition well written or should it be like this:
IF EXISTS(SELECT TOP 1 #IDTTIC = IDTTIC FROM #ProbelmTickets)

IF EXISTS(SELECT * FROM #ProblemTickets)
BEGIN
SELECT TOP 1 #IDTTIC = IDTTIC FROM #ProblemTickets
END
The Exists Clause check for exisitance of something, if it does exist it will return true and if it doesnt it will return false but you cant return data inside the Exists clause.
You can try like I have shown above
1- Check for existance of something 1st.
2- If it exists then get the top 1 value in your variable.
*Suggestion by Aaron Bertrand *
You can simply assign a value to your variable without checking for existence 1st, If there is any data in the table the value will be assigned to the variable otherwise variable remains NULL.
When assigning value to a variable in a SELECT statement make sure your SELECT is returning only one row back if which obviously you are already doing SELECT TOP 1 but to get the “Right TOP 1” row you should use ORDER BY clause as well.
Also when assigning values to variable in SELECT you cannot retrieve data at the same time, If SELECT is returning more than one column all the values retuned should be stored in a variable
Something like this ..
SELECT TOP 1 #Var1 = Col1, #Var2 = Col2, #Var3 = Col3
FROM TABLE_Name
ORDER BY Some_Column
You Cannot do something like this
SELECT TOP 1 #Var1 = Col1, #Var2 = Col2, Col3
FROM TABLE_Name
ORDER BY Some_Column

Personally, I think it should just be:
SELECT TOP (1) #IDTTIC = IDTTIC FROM #ProblemTickets ORDER BY <something>;
If there are any rows in the table, the value will be populated (unless that column can be NULL, of course). If there are no rows, the variable will still be NULL.
There is no need to say IF EXISTS and then assign the variable with another SELECT. You are just reading the table twice instead of once for no good reason.

Related

Show results from query if results exist without running the same query again

I want to have a stored procedure that will take one SerialNumber nvarchar as it's input and check several databases to see if that serial number exists and if it does exist then return the result of the query, otherwise move onto the next database and do the same thing until all databases have been checked.
Current pseudocode:
IF(exists(select top 1 * from Server1.Database1.Table where num = #SerialNumberInput))
BEGIN
select top 1 * from Server1.Database1.Table where num = #SerialNumberInput
END ELSE
IF(exists(select top 1 * from Server2.Database2.Table where num = #SerialNumberInput))
BEGIN
select top 1 * from Server2.Database2.Table where num = #SerialNumberInput
END ELSE
--Server3.Database3
--Server4.Database4
--etc...
But I don't like all this query repetition and I don't like how I'm having to make a call to the server twice by calling the same query twice. I could save the result to a table variable and just check that but that feels hacky.
Too long to comment.
But I don't like all this query repetition
Me neither, but for this case, it's the cleanest method or most readable IMHO.
I don't like how I'm having to make a call to the server twice by
calling the same query twice.
You aren't, at least not exactly. EXISTS returns a BOOLEAN value so as long as there is an INDEX on your predicate, it should be pretty fast. The second query, where you are returning the first row with all of the columns would be slightly slower. Also, you don't need top 1 * in the EXISTS unless you just like that. You can use SELECT 1 or anything since the result is BOOLEAN.
Another thing is you are using TOP without and ORDER BY which means you don't care what row is returned, and are OK with that row being different (potentially) each time you execute this. More on that in this blog.
If you really want to not use EXISTS, you can break this up using ##ROWCOUNT.
select top 1 * from Server1.Database1.Table where num = #SerialNumberInput
if ##ROWCOUNT = 1
return
else
select top 1 * from Server2.Database2.Table where num = #SerialNumberInput
if ##ROWCOUNT = 1
return
else
...
Or, if the schema is the same and you don't want NULL datasets... something like you said with the table variable.
create table #Temp(...)
insert into #Temp
select top 1 * from Server1.Database1.Table where num = #SerialNumberInput
if ##ROWCOUNT = 1
select * from #Temp
return
else
insert into #Temp
select top 1 * from Server2.Database2.Table where num = #SerialNumberInput
if ##ROWCOUNT = 1
select * from #Temp
return
else
...
Since you are only inserting a single row, it'd be pretty quick. Larger datasets would naturally take longer.

Comparing datetime value of columns from different tables

I have my sql query like this
if not exists(select RowId from dbo.Cache where StringSearched = #FirstName and colName = 'FirstName')
begin
--some code here
end
The purpose of above if statement is not to execute the piece of code inside of it if value of StringSearched is already present in Cache table which means it has been looked up before and so no need to make calculations again. The code inside of if statement if executed returns row number of rows from Table Band those are then inserted into Cache table to continue maintaining the cache. anyway .I need the records to be picked from Cache only if ModifiedAt column of Cache table is latest than ModifiedAt column of rows of Table B.
Note: I understand that I may need to use a subquery in where clause but in where clause itself, I need to check ModifiedAt column of Table B only for RowId's returned by Outer select query .
How can I proceed without making it much complex ?
You can use the subquery in the current query along with the Where clause.You didn't specified what are the columns to know for figure out which rows to get value so I assumed your tableB also has StringSearched and colName to get max(ModifiedAt) for that string vlaue.
IF NOT EXISTS (SELECT * from dbo.Cache as c WHERE StringSearched = #FirstName
AND colName = 'FirstName'
AND ModifiedAt > (Select MAX(ModifiedAt) FROM tableB as tabB WHERE tabB.RowID = c.RowID ))
BEGIN
--your query
END

Check whether a table contains rows or not sql server 2005

How to Check whether a table contains rows or not sql server 2005?
For what purpose?
Quickest for an IF would be IF EXISTS (SELECT * FROM Table)...
For a result set, SELECT TOP 1 1 FROM Table returns either zero or one rows
For exactly one row with a count (0 or non-zero), SELECT COUNT(*) FROM Table
Also, you can use exists
select case when exists (select 1 from table)
then 'contains rows'
else 'doesnt contain rows'
end
or to check if there are child rows for a particular record :
select * from Table t1
where exists(
select 1 from ChildTable t2
where t1.id = t2.parentid)
or in a procedure
if exists(select 1 from table)
begin
-- do stuff
end
Like Other said you can use something like that:
IF NOT EXISTS (SELECT 1 FROM Table)
BEGIN
--Do Something
END
ELSE
BEGIN
--Do Another Thing
END
FOR the best performance, use specific column name instead of * - for example:
SELECT TOP 1 <columnName>
FROM <tableName>
This is optimal because, instead of returning the whole list of columns, it is returning just one. That can save some time.
Also, returning just first row if there are any values, makes it even faster. Actually you got just one value as the result - if there are any rows, or no value if there is no rows.
If you use the table in distributed manner, which is most probably the case, than transporting just one value from the server to the client is much faster.
You also should choose wisely among all the columns to get data from a column which can take as less resource as possible.
Can't you just count the rows using select count(*) from table (or an indexed column instead of * if speed is important)?
If not then maybe this article can point you in the right direction.
Fast:
SELECT TOP (1) CASE
WHEN **NOT_NULL_COLUMN** IS NULL
THEN 'empty table'
ELSE 'not empty table'
END AS info
FROM **TABLE_NAME**

Optionally use a UNION from another table in T-SQL without using temporary tables or dynamic sql?

I have two sql server tables with the same structure. In a stored procedure I have a Select from the first table. Occasionally I want to select from the second table as well based on a passed in parameter.
I would like a way to do this without resorting to using dynamic sql or temporary tables.
Pass in param = 1 to union, anything else to only return the first result set:
select field1, field2, ... from table1 where cond
union
select field1, field2, ... from table2 where cond AND param = 1
If they are both the exact same structure, then why not have a single table with a parameter that differentiates the two tables? At that point, it becomes a simple matter of a case statement on the parameter on which results set you receive back.
A second alternative is dual result sets. You can select multiple result sets out of a stored procedure. Then in code, you would either use DataReader.NextResult or DataSet.Tables(1) to get at the second set of data. It will then be your code's responsibility to place them into the same collection or merge the two tables.
A THIRD possibility is to utilize an IF Statement. Say, pass in an integer with the expected possible values of 1,2, 3 and then have something along this in your actual stored procedure code
if #Param = 1 Then
Select From Table1
if #Param = 2 THEN
Select From Table2
if #Param = 3 Then
Select From Table1 Union Select From Table 2
A fourth possibility would be to have two distinct procedures one which runs a union and one which doesn't and then make it your code's responsibility to determine which one to call based on that parameter, something like:
myCommandObject.CommandText = IIf(myParamVariable = true, "StoredProc1", StoredProc2")
It's pretty easy.
/* Always return tableX */
select colA, colB
from tableX
union
select colA, colB
from tableY
where #parameter = 'IncludeTableY' /* Will union with an empty set otherwise */
If this isn't immediately apparent (it often isn't), consider the examples below. The primary thing to remember is that the if the where clause evaluates to true for a row, it is returned otherwise it's discarded.
This always evaluates to true so every row is returned.
select *
from tableX
where 1 = 1
This always evaluates to false so no rows are returned (sometimes used as a quick and dirty get-me-the-columns query).
select *
from tableX
where 1 = 0
this will return values from either table, depending on if you passed a value on the parameter
select field1, field2, ... from table1 where #p1 is null
union
select field1, field2, ... from table2 where #p1 is not null
you just need to add the rest of your criteria for the where clause
Use a view.
CREATE view_both
AS
SELECT *, 1 AS source
FROM table1
UNION ALL
SELECT *, 2 AS source
FROM table2
SELECT * FROM view_both WHERE source < #source_flag
The optimizer determines which, or both, tables to use based on source without requiring it to be indexed.

Updating a table within a select statement

Is there any way to update a table within the select_expr part of a mysql select query. Here is an example of what I am trying to achieve:
SELECT id, name, (UPDATE tbl2 SET currname = tbl.name WHERE tbl2.id = tbl.id) FROM tbl;
This gives me an error in mysql, but I dont see why this shouldn't be possible as long as I am not changing tbl.
Edit:
I will clarify why I cant use an ordinary construct for this.
Here is the more complex example of the problem which I am working on:
SELECT id, (SELECT #var = col1 FROM tbl2), #var := #var+1,
(UPDATE tbl2 SET col1 = #var) FROM tbl WHERE ...
So I am basically in a situation where I am incrementing a variable during the select statement and want to reflect this change as I am selecting the rows as I am using the value of this variable during the execution. The example given here can probably be implemented with other means, but the real example, which I wont post here due to there being too much unnecessary code, needs this functionality.
If your goal is to update tbl2 every time you query tbl1, then the best way to do that is to create a stored procedure to do it and wrap it in a transaction, possibly changing isolation levels if atomicity is needed.
You can't nest updates in selects.
What results do you want? The results of the select, or of the update.
If you want to update based on the results of a query you can do it like this:
update table1 set value1 = x.value1 from (select value1, id from table2 where value1 = something) as x where id = x.id
START TRANSACTION;
-- Let's get the current value
SELECT value FROM counters WHERE id = 1 FOR UPDATE;
-- Increment the counter
UPDATE counters SET value = value + 1 WHERE id = 1;
COMMIT;