Selecting not null column - sql

I have a table with varbinary(max) column and nvarchar(max) column. One of them is null and the other has a value.
I would like to return the column that has the value as a varbinary(max) column. So far I have tried this, that does not work:
SELECT
A =
CASE A
WHEN NULL THEN B
ELSE A
END
FROM Table

SELECT COALESCE(A, CAST(B As varbinary(max)))
UPDATE: In response to comments (thanks) and assuming B is the nvarchar(max) column, I have moved the CAST inside the COALESCE

Try SELECT ISNULL(A, cast(B AS varbinary(max))) FROM TABLE

Your case statement evaluates to the dreaded A = NULL:
CASE A WHEN NULL THEN B ELSE A END
Is the same as:
CASE WHEN A = NULL then B ELSE A END
One way to fix this is to use A IS NULL, like:
CASE WHEN A IS NULL THEN B ELSE A END
Or even simpler:
COALESCE(A,B)
Both the when and the coalesce will assume the data type of the first argument. To cast the result to varbinary, you can place the varbinary column first, or explicitly cast:
COALESCE(CAST(A AS VARBINARY(MAX)),B)

here is the full code of create table and insert value and apply my code and only retrieve not null value
CREATE TABLE [dbo].[SUPPLIER](
[ID] [int] IDENTITY(1,1) NOT NULL,
[SUPPLIER_NAME] [varchar](100) NOT NULL,
[ADDRESS] [varchar](150) NULL,
[CREATE_DATE] [datetime] NULL,)
INSERT INTO [MyPayrol].[dbo].[SUPPLIER]
([SUPPLIER_NAME]
,[CREATE_DATE])
VALUES
('Khaled Nabil'
,GETDATE())
declare #inumberofcolumn int
select #inumberofcolumn= count(*)
from sys.columns where OBJECT_NAME(object_id) = 'supplier'
declare #nameofcolumn varchar(100)
set #nameofcolumn =''
declare #counter int
set #counter=1
declare #colname varchar(100)
declare #statment varchar(100)
declare #value varchar(100)
while #counter <=#inumberofcolumn
begin
select #colname= COL_NAME(object_id('[dbo].[SUPPLIER]'),#counter)
declare #data table ([value] varchar(100))
--set #statment = 'select '+#colname+' from [dbo].[SUPPLIER]'
insert #data exec ('SELECT top 1 '+ #colname +' from [dbo].[SUPPLIER]')
select #value = [value] from #data
if #value is not null
begin
if #counter = 1
begin
set #nameofcolumn = #nameofcolumn + #colname
end
else
begin
set #nameofcolumn = #nameofcolumn + ','+ #colname
end
end
set #counter = #counter+1
end
execute ('select '+#nameofcolumn+' from [dbo].[SUPPLIER]')

Related

T-SQL function in Select to Only Return Columns with Values

I have a query that will return only columns with values. How do I add that to a function so I can use that with any query? Would it be a function in the where clause.
create table test1
(
s_no int not null,
name varchar(10) not null,
address varchar(10) null,
emailid varchar(100) null
)
insert into test1 (s_no, name)
values (1,'A'),(2,'B'),(3,'C')
declare #column_list varchar(8000),
#counter int
set #column_list = ''
set #counter = 0
while (Select max(colid) from syscolumns where id = object_id('test1') and isnullable= 0) > #counter
begin
select #counter = min(colid)
from syscolumns
where id = object_id('test1')
and isnullable = 0
and colid > #counter
select #column_list = #column_list + ',' + (Select name from syscolumns where id = object_id('test1') and isnullable= 0 and colid = #counter)
end
select #column_list = SUBSTRING(#column_list, 2, len(#column_list))
declare #sql varchar(8000)
select #sql = 'select ' + #column_list + ' from test1'
print #sql
exec (#sql)
SELECT * FROM [dbo].[test1]
I guess you could make a stored procedure where you provide the table name as parameter, and then build your query like you are doing already
create procedure ShowOnlyFilledColumns (#tablename varchar(100)) as
begin
set nocount on
declare #column_list varchar(8000),
#counter int
set #column_list = ''
set #counter = 0
while (Select max(colid) from syscolumns where id = object_id(#tablename) and isnullable= 0) > #counter
begin
select #counter = min(colid) from syscolumns where id = object_id(#tablename) and isnullable= 0 and colid > #counter
select #column_list = #column_list + ',' + (Select name from syscolumns where id = object_id(#tablename) and isnullable= 0 and colid = #counter)
end
select #column_list = SUBSTRING(#column_list,2,len(#column_list))
declare #sql varchar(8000)
select #sql = 'select ' + #column_list + ' from ' + #tablename
--print #sql
exec (#sql)
end
and use it like this
exec ShowOnlyFilledColumns 'test1'
See the complete example in this DBFiddle
EDIT: The OP asked how he can add joins on this
There are a few tricks to join with a stored procedure, for example in these answers
However, this won't work on this solution, because it requires to create a temp table to store the result of the procedure.
The trick looks like this
-- create a temporary table to store the results of the procedure
CREATE TABLE #Temp (
s_no int not null,
name varchar(10) not null,
address varchar(10) null,
emailid varchar(100) null
)
-- call the procedure and store the result in the temporary table
INSERT INTO #Temp
exec ShowOnlyFilledColumns 'test1'
-- now I can query the temp table, and join on it and write a where clause, and I can do whatever I want
select * from #Temp
Now, this won't work in this case, because the stored procedure can return different columns every time you run it, and to make the insert into #Temp exec ShowOnlyFilledColumns 'test1' work, the table #Temp must have the same number and type of columns as the procedure returns. And you just don't know that.

SQL Server : Where NULL columns from dynamic list

I'm writing a query against a table A where I want to find out if a row in table A has fields that are null. The thing is that these fields are dynamic and are found in another table B.
Normally you would write,
Table A ....
WHERE A.myField1 IS NOT NULL AND A.myField2 IS NOT NULL
But in this case I want to do
table A ....
WHERE (some columns in table **A** specified in table **B**) IS NOT NULL
Is it possible to do this?
If I understand your question correctly, you may try to generate dynamic SQL statement and execute this statement:
-- Tables
CREATE TABLE #TableA (
MyField1 int,
MyField2 int,
MyField3 int,
MyField4 int,
MyField5 int,
MyField6 int
)
CREATE TABLE #TableB (
FieldName nvarchar(50)
)
INSERT INTO #TableB
(FieldName)
VALUES
('MyField1'),
('MyField2'),
('MyField3')
-- Declarations
DECLARE
#stm nvarchar(max),
#err int
-- Statement generation
SET #stm = N''
SELECT #stm = #stm +
N'AND (' +
[FieldName] +
N' IS NOT NULL) '
FROM #TableB
SET #stm =
N'SELECT * FROM #TableA WHERE ' +
STUFF(#stm, 1, 4, N'')
-- Execution
PRINT #stm
EXEC #err = sp_executesql #stm
IF #err = 0
PRINT 'OK'
ELSE
PRINT 'Error'
Generated statement:
SELECT *
FROM #TableA
WHERE (MyField1 IS NOT NULL) AND (MyField2 IS NOT NULL) AND (MyField3 IS NOT NULL)

SQL MERGE Table with tableName

I would like have a generic procedure to Update my look Up Table.
CREATE TYPE S_Reference.[ReferenceType] as TABLE (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(16) UNIQUE NOT NULL,
[Rank] SMALLINT NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
GO
CREATE PROCEDURE [S_Reference].[P_B_ReferenceMerge]
#Values [ReferenceType] READONLY,
#TableName NVARCHAR(50)
AS
DECLARE #SQLQuery NVARCHAR(200)
SET #SQLQuery = 'SELECT * FROM ' + #TableName
MERGE INTO #SQLQuery Ori
USING
#Values New
ON (Ori.[Id] = New.[Id])
WHEN MATCHED THEN
UPDATE
SET Ori.[Code] = New.[Code],
Ori.[Rank] = New.[Rank],
Ori.[Description] = New.[Description],
Ori.[Base] = New.[Base]
WHEN NOT MATCHED THEN
INSERT (Ori.[Id] , Ori.[Code], Ori.[Rank],Ori.[Description] ,Ori.[Base])
Values (New.[Id] , New.[Code], New.[Rank],New.[Description] ,New.[Base]);
RETURN 0
But I don't know how to use the "tableName" ?
I get an error on Ori.[Id], I think the problem comes from
SET #SQLQuery = 'SELECT * FROM ' + #TableName
MERGE INTO #SQLQuery Ori
If can help this is how I did. By this way You can manage easily the values in your look up (reference or enum in c#).
First the procedure:
CREATE TYPE S_Reference.[ReferenceType] AS TABLE (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(40) UNIQUE NOT NULL,
[Rank] SMALLINT UNIQUE NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
GO
CREATE PROCEDURE [S_Reference].[P_M_ReferenceMerge]
#Values S_Reference.[ReferenceType] READONLY,
#TableName NVARCHAR(50)
AS
CREATE TABLE #NewValues (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(40) UNIQUE NOT NULL,
[Rank] SMALLINT UNIQUE NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
Insert INTO #NewValues
select * From #Values
DECLARE #SQLQuery NVARCHAR(MAX)
SET #SQLQuery =
'DELETE
FROM ' + #TableName + '
WHERE [Id] IN (SELECT [Id]
FROM ' + #TableName + '
EXCEPT
SELECT [Id]
FROM #NewValues)
MERGE INTO ' + #TableName + ' Ori
USING #NewValues New
ON (Ori.[Id] = New.[Id])
WHEN MATCHED THEN
UPDATE
SET Ori.[Code] = New.[Code],
Ori.[Rank] = New.[Rank],
Ori.[Description] = New.[Description],
Ori.[Base] = New.[Base]
WHEN NOT MATCHED THEN
INSERT ([Id] , [Code], [Rank], [Description] ,[Base])
Values (New.[Id] , New.[Code], New.[Rank], New.[Description] ,New.[Base]);'
EXEC sp_executesql #SQLQuery
RETURN 0
Usage
INSERT INTO
#VALUES([Id],[Code],[Rank],[Description] ,[Base])
Values
(1,'EUR',1,'EUR',0),
(2,'GBP',2,'GBP',0),
(3,'USD',3,'USD',0)
EXEC [S_Reference].[P_M_ReferenceMerge]
#Values = #VALUES,
#TableName = 'S_Reference.T_R_Currency'
DELETE FROM #VALUES

SQL SP: Dynamic Query

I am trying get a col and value as a function parameter and planning to use them in a query.
Unfortunately, my value for #Col is being treated like a string and not a column identifier.
ie, if I specify name as a value for the #Col parameter, it will be treated like 'name' instead of name and hence, the call to the function always returns NULL as a result
Have you came across similar situations? Could you please recommand me a better way to deal with this situation?
Here is my Function for your reference:
CREATE FUNCTION [dbo].[FN_FindIdBy]
(
#Col NVARCHAR(255),
#Value NVARCHAR(255)
)
RETURNS INT
AS
BEGIN
DECLARE #Id INT = NULL
SET #Id = (SELECT ID FROM dbo.MYWORK WHERE (CONVERT(NVARCHAR(255), #Col) = #Value))
IF #Id IS NOT NULL RETURN #Id
RETURN NULL
END
Thanks a lot for looking into this.
The following works, but you have to use it as a procedure and create dynamic sql.
create table MYWORK (ID int identity, Name nvarchar(255))
insert into MYWORK(Name)
select 'a'
union select 'b'
union select 'c'
union select 'd'
union select 'e'
union select 'f'
CREATE procedure [dbo].[EPG_FN_FindIdBy]
#Col NVARCHAR(255),
#Value NVARCHAR(255)
AS
BEGIN
DECLARE #Id nvarchar(255)
, #ParmDefinition nvarchar(255)
, #sql nvarchar(max)
set #sql = N'SELECT #IdOUT = ID FROM dbo.MYWORK WHERE '+ #Col +' = ''' + #Value + ''''
set #ParmDefinition = N'#IdOUT nvarchar(255) OUTPUT'
PRINT #sql
EXECUTE sp_executesql #sql,#ParmDefinition, #IdOUT = #Id OUTPUT
SELECT #Id as ID
END
Run this and it'll return the matching row
Exec dbo.EPG_FN_FindIdBy #Col = 'Name', #Value = 'a'
And for a NULL
Exec dbo.EPG_FN_FindIdBy #Col = 'Name', #Value = 'g'
Yeah, there's almost always a better way to query than using dynamic SQL.
Check out this usage of the CASE operator.
SELECT id
FROM dbo.MYWORK
WHERE CASE #Col
WHEN 'a' THEN [a]
WHEN 'b' THEN [b]
WHEN 'c' THEN [c]
END = #Value
Where the table has columns [a], [b] and [c].

Does this query require dynamic sql? SQL Server

I want to select the parameters of a stored procedure and then check whether each parameter is null or not in a loop.
The problem I'm having is that when I want to evaluate the variable in the IF statement, it is not being evaluated correctly. I want to evaluate each parameter I stored in the table variable. I don't know the syntax for this...or maybe it isn't even possible?
Does this require Dynamic SQL? If so, when executing dynamic sql, the value of the variable will be out of scope so how do I deal with that?
I verified everything up to the IF statement works.
CREATE PROCEDURE dbo.UpdateBank
(
#BankKey [smallint] = NULL,
#Bank [varchar] (30) = NULL,
#BankCode [char] (4) = NULL,
#MasterBankCode [char] = NULL,
#Bin [char] (6) = NULL,
#WebSite [varchar] (50) = NULL,
#isActive [bit] = NULL,
#CreateDate [smalldatetime] = NULL
)
AS
SET NOCOUNT ON
SET ANSI_NULLS OFF
DECLARE #MaxRow TINYINT, #Count TINYINT
DECLARE #SPName VARCHAR (128), #CurrentRow TINYINT
SET #SPName = OBJECT_NAME(##PROCID) -- SP self-reference to find its current name
DECLARE #SPParametersList TABLE (ID INT Identity(1,1) Primary Key,
ParameterName NVARCHAR (128),
DataType NVARCHAR (128),
ParameterMode NVARCHAR (10))
CREATE TABLE #TempExec(ID INT Identity(1,1) Primary Key,
Num BIT)
INSERT INTO #SPParametersList (ParameterName, Datatype, ParameterMode)
SELECT PARAMETER_NAME,DATA_TYPE,PARAMETER_MODE
FROM INFORMATION_SCHEMA.PARAMETERS
WHERE SPECIFIC_NAME = #SPName
SET #CurrentRow = 1
SELECT #MaxRow = ISNULL(MAX(ID),0) FROM #SPParametersList
WHILE #CurrentRow <= #MaxRow
BEGIN
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) <> NULL)
BEGIN
SELECT 'Success'
SET #Count = #Count + 1
END
SELECT 'Fail'
SET #CurrentRow = #CurrentRow + 1
END
SELECT #Count
I always get 'Fail' when I run this stored proc
Change your line:
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) <> NULL)
to
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) IS NOT NULL)
You also need to initialize the #Count variable to 0:
SET #Count = 0
SET #CurrentRow = 1
SELECT #MaxRow = ISNULL(MAX(ID),0) FROM #SPParametersList
Probably the issue is in the <> NULL which should
IF EXISTS(SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow)
but I'm not sure what you want to achieve with that piece of code...
I suspect that this is an example of a query that can be rewritten without the use of loops/cursors (most sql is in my experience...)
Does the query below give you your desired results?
with temp as
(
SELECT '#BankKey' as ParamName
UNION
SELECT '#Bank'
)
SELECT COUNT(*) as myCount
FROM INFORMATION_SCHEMA.PARAMETERS as isp
LEFT JOIN temp as t
ON t.ParamName = isp.PARAMETER_NAME
WHERE SPECIFIC_NAME = #SPName AND t.ParamName is null
You should try to avoid using Loops/Cursors as much as possible. SQL Server (and most DBMSs in general) are excellent at performing Set based operations and terrible at performing row based operations (loops/cursors).
(1) "I always get 'Fail' when I run this stored proc": you have forget the ELSE branch
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) /*<>*/ IS NOT NULL)
BEGIN
SELECT 'Success'
SET #Count = #Count + 1
END
ELSE -- << here
BEGIN
SELECT 'Fail'
END
SET #CurrentRow = #CurrentRow + 1
(2) To count all not null parameters:
SELECT #Count=COUNT(*)
FROM #SPParametersList a
WHERE a.ParameterName IS NOT NULL
To count all null parameters:
SELECT #Count=COUNT(*)
FROM #SPParametersList a
WHERE a.ParameterName IS NULL
Note: if you want to test for NULL / NOT NULL you should use column/#variable IS [NOT] NULL operator and SET ANSI_NULLS must be ON: SET ANSI_NULLS ON.