TSQL - ISNULL over multiple columns - sql

I have a simple SQL query (SQL Server 2005) where I'm selecting from a table that contains multiple columns that have BIT values.
These columns are nullable so can contain NULL, 0 or 1.
There are a fair number of these columns and in my query I want to return zero if the value is NULL.
I'm currently using ISNULL like so:
SELECT Name, Age, ISNULL(LikesOranges,0), ISNULL(LikesApples,0), ISNULL(LikesPears,0)
FROM FoodPreferences
As I've mentioned, there are a lot of these BIT columns (much more than in the simple example above).
Is there a way I can use ISNULL over multiple columns like this:
SELECT ISNULL(*,0) FROM FoodPreferences
The above query doesn't work but you get what I'm trying to do - so I can avoid having to write an ISNULL statement for each column,
Thanks.

Try this:
SELECT COALESCE(LikesOranges, LikesApples, LikesPears) AS MyBit FROM FoodPreferences
This will return the first non-null value. If all fields are NULL the result is NULL.
UPDATE:
And the conclusion is:
SELECT ISNULL(COALESCE(LikesOranges, LikesApples, LikesPears),0) AS MyBit FROM FoodPreferences

so I can avoid having to write an
ISNULL statement for each column,
Run this query and copy the result to your select statement. system_type_id = 104 filters the result on bit columns.
select stuff((select ', isnull('+name+', 0)'
from sys.columns
where object_id = object_id('FoodPreferences') and
system_type_id = 104
for xml path('')), 1, 1, '')
Result:
-------------------------------------------------------------------------
isnull(LikesOranges, 0), isnull(LikesApples, 0), isnull(LikesPears, 0)

I don't think so. But an option might be to create a view onto that table and put all the ISNULL statements in the view. At least then you won't have to do it every time
eg.
CREATE VIEW vwFoodPreferences
AS
SELECT Name,
Age,
ISNULL(LikesOranges,0) AS LikesOranges,
ISNULL(LikesApples,0) AS LikesApples,
ISNULL(LikesPears,0) AS LikesPears
FROM FoodPreferences

Unfortunately, the simple answer is no.
You could write sql dynamically, but whatever happens, the final resulting sql would have to be ISNULL(a,0), ISNULL(b,0), ISNULL(c,0), ISNULL(d,0), etc

i think you can write a simple program and generate select clause by reading all columns and generating the select

while not this :
SELECT COALESCE(LikesOranges, LikesApples, LikesPears, 0) AS MyBit FROM FoodPreferences
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/coalesce-transact-sql?view=sql-server-2017

Related

With as in Oracle SQL

I would like to know if is it possible to use the clause "with as" with a variable and/or in a block begin/end.
My code is
WITH EDGE_TMP
AS
(select edge.node_beg_id,edge.node_end_id,prg_massif.longueur,prg_massif.lgvideoupartage,prg_massif.lgsanscable from prg_massif
INNER JOIN edge on prg_massif.asset_id=edge.asset_id
where prg_massif.lgvideoupartage LIKE '1' OR prg_massif.lgsanscable LIKE '1')
,
journey (TO_TOWN, STEPS,DISTANCE,WAY)
AS
(SELECT DISTINCT node_beg_id, 0, 0, CAST(&&node_begin AS VARCHAR2(2000))
FROM EDGE_TMP
WHERE node_beg_id = &&node_begin
UNION ALL
SELECT node_end_id, journey.STEPS + 1
, journey.DISTANCE + EDGE_TMP.longueur,
CONCAT(CONCAT(journey.WAY,';'), EDGE_TMP.node_end_id
)
It create a string as output separated by a ; but i need to get it back as variable or table do you know how? I used a concat to retrieve data in a big string. Can i use a table to insert data
,
A need to use the result to proceed more treatment.
Thank you,
mat
No, WITH is a part of an SQL statement only. But if you describe why you need it in pl/sql, we'll can advice you something.
Edit: if you have SQL statement which produces result you need, you can assign it's value to pl/sql variable. There are several methods to do this, simpliest is to use SELECT INTO statement (add INTO variable clause into your select).
You can use WITH clause as a part of SELECT INTO statement (at least in not-too-very-old Oracle versions).

SQL Query with if statement

I have a table which has a `department` column (allows null) but when I select that table and the field is null I don't want it to show Null but "-".
I'm told to put the if statement inside the select statement but I can't figure it out. How can I do this?
You want to use the function coalesce():
select coalesce(department, '-')
from table t
This is an ANSI standard function available in most databases.
You can use two methods:
1. Using CASE:
SELECT CASE WHEN department IS NULL
THEN '-'
ELSE department
END AS department FROM TableName
CASE evaluates a list of conditions and returns one of multiple possible result expressions. Read more here.
2. Using COALESCE:
SELECT COALESCE (department,'-') FROM TableName
COALESCE returns first parameter which is not null. Read more here.
You need to use the 'CASE WHEN' statement in your select query. Like this:
SELECT CASE WHEN Department IS NULL THEN Department = '-'
END AS DEPARTMENT
FROM Table_Name
You can use following code:
select ISNULL(department, '-') AS DEPARTM
from dbo.tbl_Department

Parse values from one column into multiple columns in another table

Microsoft SQL Server 2008
I have two tables. One has a column in it with data that is _ delimited
example:
Y_21_CA
<BR>
such that:
Yes/No_Age_State
I need to parse the data in this column out and insert it into another table that has individual columns for each value. Let's say Table A contains one column like the example above but Table B contains three columns, YesOrNo, Age, usState.
What's the easiest way to do this? I've tried doing something like:
UPDATE TableA
SET YesOrNo = SUBSTRING (TableB.Column1, 1, 1)
but SUBSTRING only takes an expression. I really just need some guidance here, I've been banging my head against the wall trying to figure this out since I'm not much of a SQL guru. I can figure out the syntax no problem but maybe I'm not aware of some methods that exist. Thanks
A generic solution, using Charindex of '_' without hardcoding it
declare #s varchar(10) = 'Y_21_CA'
SELECT LEFT(#s, CHARINDEX('_',#s,1)-1) YN,
SUBSTRING(#s, CHARINDEX('_',#s,1)+1,
CHARINDEX('_',#s,CHARINDEX('_',#s,1)) ) Age,
RIGHT(#s, CHARINDEX('_',reverse(#s),1)-1) State
--Results
Y 21 CA
In case you expect to use this logic often in other queries, you could make the SELECT statement an inline TVF. Then you would be able to use it with your update like this:
UPDATE b
SET YesOrNo = x.YN,
Age = x.Age,
State = x.State
FROM TableB b
INNER JOIN TableA a ON b.ID = a.ID
CROSS APPLY ThreeColumnSplit(a.S) x;
Here's a "live" demo at SQL Fiddle. (Please never mind its using the SQL Server 2012 engine. That's only because the Fiddle's 2008 instance appears to be down at the moment and can't be used. There's nothing SQL Server 2012-specific in the script.)
You should be able to use the following, I think you want an INSERT instead of UPDATE.
The SELECT statement to get the data is:
select substring(yourCol, 1, 1) YesOrNo,
substring(yourcol, 3, len(yourcol)-5) Age,
right(yourCol, 2) usState
from tableA;
See SQL Fiddle with Demo
Then the INSERT statement is:
insert into tableB (YesOrNo, Age, usState)
select substring(yourCol, 1, 1) YesOrNo,
substring(yourcol, 3, len(yourcol)-5) Age,
right(yourCol, 2) usState
from tableA;
See SQL Fiddle with Demo
Note: This assumes that the YesOrNo column will always only have one character and that the usState will always have 2 characters.

How do you query an int column for any value?

How can you query a column for any value in that column? (ie. How do I build a dynamic where clause that can either filter the value, or not.)
I want to be able to query for either a specific value, or not. For instance, I might want the value to be 1, but I might want it to be any number.
Is there a way to use a wild card (like "*"), to match any value, so that it can be dynamically inserted where I want no filter?
For instance:
select int_col from table where int_col = 1 // Query for a specific value
select int_col from table where int_col = * // Query for any value
The reason why I do not want to use 2 separate SQL statements is because I am using this as a SQL Data Source, which can only have 1 select statement.
Sometimes I would query for actual value (like 1, 2...) so I can't not have a condition either.
I take it you want some dynamic behavior on your WHERE clause, without having to dynamically build your WHERE clause.
With a single parameter, you can use ISNULL (or COALESCE) like this:
SELECT * FROM Table WHERE ID = ISNULL(#id, ID)
which allows a NULL parameter to match all. Some prefer the longer but more explicit:
SELECT * FROM Table WHERE (#id IS NULL) OR (ID = #id)
A simple answer would be use: IS NOT NULL. But if you are asking for say 123* for numbers like 123456 or 1234 or 1237 then the you could convert it to a varchar and then test against using standard wild cards.
In your where clause: cast(myIntColumn as varchar(15)) like '123%'.
Assuming the value you're filtering on is a parameter in a stored procedure, or contained in a variable called #Value, you can do it like this:
select * from table where #Value is null or intCol = #Value
If #Value is null then the or part of the clause is ignored, so the query won't filter on intCol.
The equivalent of wildcards for numbers are the comparators.
So, if you wanted to find all positive integers:
select int_col from table where int_col > 0
any numbers between a hundred and a thousand:
select int_col from table where int_col BETWEEN 100 AND 1000
and so on.
I don't quite understand what you're asking. I think you should use two different queries for the different situations you have.
When you're not looking for a specific value:
SELECT * FROM table
When you are looking for a specific value:
SELECT * FROM table WHERE intcol = 1
You can use the parameter as a wildcard by assigning special meaning to NULL:
DECLARE #q INT = 1
SELECT * FROM table WHERE IntegerColumn = #q OR #q IS NULL
This way, when you pass in NULL; you get all rows.
If NULL is a valid value to query for, then you need to use two parameters.
If you really want the value of your column for all rows on the table you can simply use
select int_col
from table
If you want to know all the distinct values, but don't care how many times they're repeated you can use
select distinct int_col
from table
And if you want to know all the distinct values and how many times they each appear, use
select int_col, count(*)
from table
group by int_col
To have the values sorted properly you can add
order by int_col
to all the queries above.
Share and enjoy.

How can I limit columns returned based on their value?

I have a table which looks like
index customer_number ABC CWD ROE BEE
1 1 0 0 0 1
and I want to return only the field names that have value 1 in this case 'BEE'
I found that by SHOW FIELDS I can get the names of the fields but how I can say show the field names where field value = 1?
I would use CASE statement here.
SELECT
index, customer_number,
CASE
WHEN abc=0 THEN 'abc'
WHEN cwd=0 THEN 'cwd'
END
FROM
table_name
You can't do this in a general way.
What you can do is write a sql statement like this:
select index, customer_number, decode (ABC, 1, "ABC", null) || decode (CWD, 1, "CWD", null) || decode (ROE, 1, "ROE", null) || decode (BEE, 1, "BEE", null) from aTable
It will display the column names for each entry where the value equals to one. It is oracle sql, so if you use a different rdbms the syntax will vary.
The beat it to death answer is to use CASE statements, one for each column. Something like:
SELECT CASE WHEN index=1 THEN "index" ELSE "no_index" END as i,
CASE WHEN customer=1 THEN "customer" ELSE "no_customer" END as c,
CASE WHEN ...
This is not something that SQL was really meant to do, and would be better done with application logic.
That said, if you really wanted to do it, you would probably need to involve a temp table and a SPROC:
Get the row and determine which fields are set.
Use that information to create a temp table with only the set fields.
Insert the data into that temp table, then select the rows from there.
It would be a huge mess of SQL to replace what would amount to only a few lines of application code. Probably not worth it.