SQL Server variables - sql

Why do these queries return different values? The first returns a result set as expected, but the second (which as far as I can tell is exactly the same) does not. Any thoughts?
1:
declare #c varchar(200)
set #c = 'columnName'
select top 1 *
from myTable
where #c is not null
and len(convert(varchar, #c)) > 0
2:
SELECT top 1 *
FROM myTable
WHERE columnName IS NOT NULL
and len(convert(varchar,columnName)) > 0

It's because they aren't the same query -- your variable text does not get inlined into the query.
In query 1 you are validating that #c is not null (true, you set it) and that its length is greater than 0 (true, it's 10). Since both are true, query 1 becomes:
select top 1 * from myTable
(It will return the first row in myTable based on an appropriate index.)
EDIT: Addressing the comments on the question.
declare #myTable table
(
columnName varchar(50)
)
insert into #myTable values ('8')
declare #c nvarchar(50)
set #c = 'columnName'
select top 1 *
from #myTable
where #c is not null
and len(convert(varchar, #c)) > 0
select top 1 *
from #myTable
where columnName is not null
and len(convert(varchar,columnName)) > 0
Now when I run this both queries return the same result. You'll have to tell me where I'm misrepresenting your actual data / query to get more help (or just expand upon this to find a solution).

In the first query, you are checking the value 'columnName' against the parameters IS NOT NULL and length > 0. In the second query, you are checking the values in the columnName column against those parameters.
It should be noted that query 1 will always return one row (assuming a row exists), where query 2 will only return a row if the contents of columnName are not null and length > 0.

The first query actually evaluates as
select top 1 * from myTable where 'columnName' is not null and len(convert(varchar, 'columnName' )) > 0
Not as what you were hoping for.expected.

The two querys are not the same as in the second query you are evaluating the actual value of the field columnname. The following is the equivalent of your first function.
SELECT top 1 * FROM myTable WHERE 'columnName' IS NOT NULL and len(convert(varchar,'columnName')) > 0

They're not the same - the first is checking the variable while the second is checking the column. "where #c is not null" means where the variable #c isn't null - which it isn't, since it contains the value 'columnName'. "where columnName is not null" means where the field columnName doesn't contain a null. And the same for the evaluation of the length.

Related

How can I generate a sequence number in a empty table

I am trying to make a query that can generate the latest sequence number +1 to the new record in sql server.
let ignore the insert part first, I write a query like this:
SELECT 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1
It looks fine, when the record with same prefix exists, It return 1, else 0.
Because I have to process the current latest sequence number in the true value part, so I change my query with this to get the pk_sales_inv_no for the true part processing.
SELECT TOP (1) 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1 FROM salesInvoice WHERE (pk_sales_inv_no LIKE 'Q-ARF2206-%') ORDER BY pk_sales_inv_no DESC
Then problem happens, because the select result is totally empty, so It doesn't return the 1 or 0.
How can I improve it to work out with a empty select result.
You can write a simple scalar udf, if you need it in JOIN adapt it as a table value function.
I doubt that this is what you need, I think you want to get the number after the 2nd dash
IF OBJECT_ID (N'dbo.udf_lastSequence') IS NOT NULL
DROP FUNCTION dbo.udf_lastSequence
GO
CREATE FUNCTION dbo.udf_lastSequence (#invNo varchar(100))
RETURNS int
AS
BEGIN
DECLARE #lastInvNo VARCHAR(100)
DECLARE #search VARCHAR(100)
DECLARE #result int
SET #result = 0
SET #search = CONCAT(#invNo, '%');
SELECT TOP 1 #lastInvNo = pk_sales_inv_no
FROM salesInvoice
WHERE (pk_sales_inv_no LIKE #search)
ORDER BY pk_sales_inv_no DESC
IF #lastInvNo IS NOT NULL
SET #result = CAST(REPLACE(#lastInvNo, #invNo, '') AS INT);
return #result
END
GO
Try it with SELECT dbo.udf_lastSequence('Q-ARF2206-') WITHOUT the final % charter

Dynamic TOP N / TOP 100 PERCENT in a single query based on condition

A local variable #V_COUNT INT. If the variable #V_COUNT is '0'(zero) the return all the records from table otherwise return the number of {#V_COUNT} records from table. For example if #V_COUNT = 50, return TOP 50 records. If #V_COUNT is 0 then return TOP 100 PERCENT records. Can we achieve this in a single query?
Sample query :
DECLARE #V_COUNT INT = 0
SELECT TOP (CASE WHEN #V_COUNT > 0 THEN #V_COUNT ELSE 100 PERCENT END) *
FROM MY_TABLE
ORDER BY COL1
Incorrect syntax near the keyword 'percent'
A better solution would be to not use TOP at all - but ROWCOUNT instead:
SET ROWCOUNT stops processing after the specified number of rows.
...
To return all rows, set ROWCOUNT to 0.
Please note that ROWCOUNT is recommended to use only with select statements -
Important
Using SET ROWCOUNT will not affect DELETE, INSERT, and UPDATE statements in a future release of SQL Server. Avoid using SET ROWCOUNT with DELETE, INSERT, and UPDATE statements in new development work, and plan to modify applications that currently use it. For a similar behavior, use the TOP syntax.
DECLARE #V_COUNT INT = 0
SET ROWCOUNT #V_COUNT -- 0 means return all rows...
SELECT *
FROM MY_TABLE
ORDER BY COL1
SET ROWCOUNT 0 -- Avoid side effects...
This will eliminate the need to know how many rows there are in the table
Be sure to re-set the ROWCOUNT back to 0 after the query, to avoid side effects (Good point by Shnugo in the comments).
Instead of 100 percent you can write some very big number, which will surely be bigger than possible number of rows returned by the query, eg. max int which is 2147483647.
You can do something like:
DECLARE #V_COUNT INT = 0
SELECT TOP (CASE WHEN #V_COUNT > 0 THEN #V_COUNT ELSE (SELECT COUNT(1) FROM MY_TABLE) END) *
FROM MY_TABLE
DECLARE #V_COUNT int = 3
select *
from
MY_TABLE
ORDER BY
Service_Id asc
offset case when #V_COUNT >0 then ((select count(*) from MY_TABLE)- #V_COUNT) else #V_COUNT end rows
SET ROWCOUNT forces you into procedural logic. Furthermore, you'll have to provide an absolute number. PERCENT would need some kind of computation...
You might try this:
DECLARE #Percent FLOAT = 50;
SELECT TOP (SELECT CAST(CAST((SELECT COUNT(*) FROM sys.objects) AS FLOAT)/100.0 * CASE WHEN #Percent=0 THEN 100 ELSE #Percent END +1 AS INT)) o.*
FROM sys.objects o
ORDER BY o.[name];
This looks a bit clumsy, but the computation will be done once within microseconds...

Behaviour of SELECT #Var and SET #Var in T-SQL when dealing with NULLs

Everyday I learn something new, it seems :) Can someone please explain to me the rationale behind the following code behavior:
DECLARE #A INT
SET #A = 15
SET #A = (SELECT ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound')
SELECT #A
-- Rsultset is NULL
SET #A = 15
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
SELECT #A
-- Resultset is 15
From what I see, SET changes the value of the variable if the resultset is NULL, while SELECT doesn't. Is this normal ANSI behavior or is it T-SQL specific?
Of, course, if I do SELECT #A = NULL, the assignment happens correctly.
The first version sets A to the result of a query:
SET #A = (SELECT ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound')
Basically the select in in scalar context, and if it doesn't find a row, it evaluates to null.
The second version sets A for each row in the result set:
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
Since there are no rows, A is never assigned to. Another example:
declare #a int
select #a = i
from (
select 1
union all select 2
union all select 3
) as SubQueryAlias(i)
order by
i
select #a
This will assign 3 values to #a. The last one assigned is 3, so that's what the query prints.
Well the select returns no rows. So practically there is not assignment.
While the set will have a null as a result.
Variable assignment in a SELECT clause is rather unpredictable. When you have:
SELECT #A = ...
and exactly one row is in the result set, the value is well defined. If multiple rows are returned, the value may be computed once, for an arbitrary row, or it may be computed multiple times, up to the number of rows in the result set.
However, if the query produces zero rows, then the assignment is never performed.
SET #A = (SELECT ValueThatDoesntExist
FROM dbo.MyTable WHERE MyColumn = 'notfound')
Here NULL is returned as a result of executing the query
But when you do
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
there is nothing returned from the query

ISNULL function in SQL Server 2008 not working properly

Assume this script:
DECLARE #result TABLE(Id BIGINT);
DELETE FROM [Products].[Product]
OUTPUT DELETED.[Id] INTO #result
WHERE [Products].[Product].[Id] = 1589;
So in continues I try :
1
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
When [Id] is null returned null (nothing), but this one returned -1:
2
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
SELECT CAST(ISNULL(#mi, -1) AS BIGINT) AS N'RetValId'
Why? where is the problem with first script?
Update
So is there any way to check if the Deleted Id is null returned -1 And if not Returned Id without declare another variable? what is the simplest way?
If you have no entry for the ID 1589, then in the DELETED table there will be no record, if you have it then it should return 1589.
So if you don't have I think it simple returns nothing, because this statement has no input row:
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
(If you SELECT * from #result it should be no rows there)
The second one return the -1 because you set first to the variable which is getting the NULL value after the select.
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
(If you select only #mi after this, then it should be NULL)
I think that is the explanation
UPDATED:
May you can try a small trick to achive it without an other varriable:
SELECT CAST(ISNULL(MAX([ID]),-1) AS BIGINT) AS N'RetValId' FROM #result;
Because of MAX the insie statement will be NULL, so here is the trick. If something was deleted, then the ID will be there.
I hope it helped.
You can use a derived table that will return one row with -1 and then do an outer apply on #result.
select isnull(R.Id, T.Id) RetValId
from (values(-1)) as T(Id)
outer apply #result as R
An easy way to return null if no rows where deleted is the ##rowcount variable. It contains the number of rows affected by the previous operation:
DELETE FROM [Products].[Product]
WHERE [Products].[Product].[Id] = 1589;
IF ##ROWCOUNT = 0
return null
return 1589

SQL Query to check if 40 columns in table is null

How do I select few columns in a table that only contain NULL values for all the rows?
Suppose if Table has 100 columns, among this 100 columns 60 columns has null values.
How can I write where condition to check if 60 columns are null.
maybe with a COALESCE
SELECT * FROM table WHERE coalesce(col1, col2, col3, ..., colN) IS NULL
where c1 is null and c2 is null ... and c60 is null
shortcut using string concatenation (Oracle syntax):
where c1||c2||c3 ... c59||c60 is null
First of all, if you have a table that has so many nulls and you use SQL Server 2008 - you might want to define the table using sparse columns (http://msdn.microsoft.com/en-us/library/cc280604.aspx).
Secondly I am not sure if coalesce solves the question asks - it seems like Ammu might actually want to find the list of columns that are null for all rows, but I might have misunderstood. Nevertheless - it is an interesting question, so I wrote a procedure to list null columns for any given table:
IF (OBJECT_ID(N'PrintNullColumns') IS NOT NULL)
DROP PROC dbo.PrintNullColumns;
go
CREATE PROC dbo.PrintNullColumns(#tablename sysname)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #query nvarchar(max);
DECLARE #column sysname;
DECLARE columns_cursor CURSOR FOR
SELECT c.name
FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.name = #tablename AND c.is_nullable = 1;
OPEN columns_cursor;
FETCH NEXT FROM columns_cursor INTO #column;
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #query = N'
DECLARE #c int
SELECT #c = COUNT(*) FROM ' + #tablename + ' WHERE ' + #column + N' IS NOT NULL
IF (#c = 0)
PRINT (''' + #column + N''');'
EXEC (#query);
FETCH NEXT FROM columns_cursor INTO #column;
END
CLOSE columns_cursor;
DEALLOCATE columns_cursor;
SET NOCOUNT OFF;
RETURN;
END;
go
If you don't want to write the columns names, Try can do something like this.
This will show you all the rows when all of the columns values are null except for the columns you specified (IgnoreThisColumn1 & IgnoreThisColumn2).
DECLARE #query NVARCHAR(MAX);
SELECT #query = ISNULL(#query+', ','') + [name]
FROM sys.columns
WHERE object_id = OBJECT_ID('yourTableName')
AND [name] != 'IgnoreThisColumn1'
AND [name] != 'IgnoreThisColumn2';
SET #query = N'SELECT * FROM TmpTable WHERE COALESCE('+ #query +') IS NULL';
EXECUTE(#query)
Result
If you don't want rows when all the columns are null except for the columns you specified, you can simply use IS NOT NULL instead of IS NULL
SET #query = N'SELECT * FROM TmpTable WHERE COALESCE('+ #query +') IS NOT NULL';
Result
[
Are you trying to find out if a specific set of 60 columns are null, or do you just want to find out if any 60 out of the 100 columns are null (not necessarily the same 60 for each row?)
If it is the latter, one way to do it in oracle would be to use the nvl2 function, like so:
select ... where (nvl2(col1,0,1)+nvl2(col2,0,1)+...+nvl2(col100,0,1) > 59)
A quick test of this idea:
select 'dummy' from dual where nvl2('somevalue',0,1) + nvl2(null,0,1) > 1
Returns 0 rows while:
select 'dummy' from dual where nvl2(null,0,1) + nvl2(null,0,1) > 1
Returns 1 row as expected since more than one of the columns are null.
It would help to know which db you are using and perhaps which language or db framework if using one.
This should work though on any database.
Something like this would probably be a good stored procedure, since there are no input parameters for it.
select count(*) from table where col1 is null or col2 is null ...
Here is another method that seems to me to be logical as well (use Netezza or TSQL)
SELECT KeyColumn, MAX(NVL2(TEST_COLUMN,1,0) AS TEST_COLUMN
FROM TABLE1
GROUP BY KeyColumn
So every TEST_COLUMN that has MAX value of 0 is a column that contains all nulls for the record set. The function NVL2 is saying if the column data is not null return a 1, but if it is null then return a 0.
Taking the MAX of that column will reveal if any of the rows are not null. A value of 1 means that there is at least 1 row that has data. Zero (0) means that each row is null.
I use the below query when i have to check for multiple columns NULL. I hope this is helpful . If the SUM comes to a value other than Zero , then you have NULL in that column
select SUM (CASE WHEN col1 is null then 1 else 0 end) as null_col1,
SUM (CASE WHEN col2 is null then 1 else 0 end) as null_col2,
SUM (CASE WHEN col3 is null then 1 else 0 end) as null_col3, ....
.
.
.
from tablename
you can use
select NUM_NULLS , COLUMN_NAME from all_tab_cols where table_name = 'ABC' and COLUMN_NAME in ('PQR','XYZ');