Computed columns with null - sql

I am creating a view (using MS sql 2008) with creates a calculated field as a COLUMN1 + COLUMN2. Everything is fine and dandy but: Both COLUMN1 and COLUMN2 can be NULL.
I want to follow the following rule:
2 + 2 = 4
2 + NULL = 2
NULL + 2 = 2
0 + 0 = 0
NULL + NULL = NULL
If I use ISNULL(column2, 0), then all the rules will be followed but not the last one.
How do I need to create the view
CREATE VIEW dbo.test
AS
SELECT COLUMN1, COLUMN2, (????????) AS CALCULATEDCOL FROM dbo.TabTest;
GO

create view dbo.test AS
select
column1,
column2,
case
when column1 is null and column2 is null then null
-- or when isnull(column1, column2) is null then null
else isnull(column1, 0) + isnull(column2, 0)
end as CALCULATEDCOL
from dbo.TabTest

CASE
WHEN COALESCE(COLUMN1, COLUMN2) IS NULL THEN NULL
ELSE ISNULL(COLUMN1, 0) + ISNULL(COLUMN2, 0)
END

You can do this without a case statement:
select coalesce(column1+column2,
coalesce(column1, 0) + column2,
column1 + coalesce(column2, 0)
)
(The function coalesce is equivalent to isnull, except coalesce is standard SQL and can take more than two arguments.)
There is no disadvantage to using the case statement. I'm just offering this as an alternative.

Use CASE expression instead. Like so:
CREATE VIEW dbo.test AS
SELECT
COLUMN1,
COLUMN2,
CASE
WHEN COLUMN1 IS NULL AND COLUMN2 IS NULL THEN NULL
WHEN COLUMN1 IS NULL THEN 0 + COLUMN2
WHEN COLUMN2 IS NULL THEN 0 + COLUMN1
ELSE COLUMN1 + COLUMN2
END AS CALCULATEDCOL
FROM dbo.TabTest;
GO

it is more simple than people would expect, using CASE for this question is a waste when there is a standard function called COALESCE, just replace your questionmarks with this:
COALESCE(col1 + col2, col1, col2)

You rule seems to be "Treat nulls as zero unless both fields are null, in which case, return null." I would approach this with a case, to separate the two rules:
CASE WHEN column1 is null and column2 is null then null
ELSE ISNULL(column1,0) + ISNULL(column2,0)
END

You can use a CASE to handle the last condition:
CREATE VIEW dbo.test
AS
SELECT column1,
column2,
CASE
WHEN column1 IS NULL
THEN column2 + 0
WHEN column2 IS NULL
THEN column1 + 0
WHEN column1 IS NOT NULL AND column2 IS NOT NULL
THEN column1 + column2
ELSE NULL
END AS calculatedcol
FROM dbo.tabtest;

Using a case system, you can handle when both values are null from when either of them is NULL
CREATE VIEW dbo.test
AS
SELECT COLUMN1, COLUMN2,
CASE WHEN (COLUMN1 IS NULL AND COLUMN2 IS NULL) THEN NULL
ELSE ISNULL(COLUMN1,0)+ISNULL(COLUMN2,0)
END AS CALCULATEDCOL
FROM dbo.TabTest;
GO

You can use the case keyword to achieve this.
Something on these lines
SELECT CASE
WHEN COLUMN1 IS NULL AND COLUMN2 IS NULL THEN NULL
WHEN COLUMN1 IS NULL AND... etc...

Related

What do the quotes mean in this SQL Server snippet? (SELECT '' column1, '' column 2)

I'd like to know the purpose of the two single quotes in front of each column. This is in a stored procedure. Thank you for your help!
INSERT INTO #temptable1
SELECT DISTINCT '' column1
,column2
,'' column3
,'' column4
FROM table1
WHERE column1 NOT LIKE 'string1%'
AND column2 <> 'string2'
AND column3 <> 'string3'
The expression '' is an empty string. So this is using an empty string instead of NULL for "missing" values.
I would write this code as:
SELECT DISTINCT '' as column1, column2, '' as column3, '' as column4
This might make it clearer. I always use as for column aliases -- so it is easier to spot missing commas (there should always be an as for a column alias).
More commonly, this would probably just use default values (which are usually NULL but could be ''):
INSERT INTO #temptable1 (column2)
SELECT DISTINCT column2
FROM table1
WHERE column1 NOT LIKE 'string1%'
AND column2 <> 'string2'
AND column3 <> 'string3';

Change column being used in WHERE condition based on IF condition

I apologize for the title - i was struggling coming up with something better.
Been doing some research on this and did find some close examples, however this is not quite what i need.
Basically i have a table with two columns that i want to evaluate under certain conditions. Column 1 is a identifier that can also be null. Column 2 is a SessionId that can change also.
Primarily i key off of column1, but when column1 is null i would like to key off of column2 instead. The example i linked above doesn't change the column being evaluated in the WHERE clause, only the value being used to evaluate the clause.
Here is some pseudo code to illustrate what i am trying to do:
SELECT * FROM MyTable
WHERE
IF Column1 NOT NULL
Column1 = #myvariable1
ELSE
Column2 LIKE '%' + #myvariable2 + '%'
Is something like this even possible? Can i switch the column to be evaluated in the WHERE clause based on the value of one of the columns?
I hope all that makes sense.
TIA
You could use CASE:
SELECT *
FROM MyTable
WHERE (CASE WHEN Column1 IS NOT NULL AND Column1 = #myvariable1 THEN 1
WHEN Column2 LIKE '%' + #myvariable2 + '%' THEN 1
ELSE 0
END) = 1;
You should check for nullable on Column1 on both validation of the where clause in case you set #myvariable1 to null.
SELECT * FROM MyTable
WHERE (Column1 IS NOT NULL AND Column1 = #myvariable1)
OR (Column1 IS NULL and Column2 LIKE '%' + #myvariable2 + '%')
WHERE Column1 = #myvariable1
OR ( Column1 IS NULL AND Column2 LIKE '%' + #myvariable2 + '%' )

SQL: How to check a value in column is equal to the sum of any combination of the other columns in a row

I came across a scenario where I have a table structure as such:
Column0 Column1 Column2 Column3 Column4 Column5
100 U V X Y Z
I need to find if:
100 = U, V, X, Y, or Z.
100 = X + Y + Z + V
100 = X + Y
100 = V + Z
etc.
Any suggestions of how I can achieve this?
Case statements will take forever to write. I do not write PL/SQL code but I am familiar with it somewhat.
Writing the Case statement isn't as hard as you're implying. I generated the following Case statement using a text editor in about 20 seconds, which should handle all situations in your example:
Select Case
When Column0 = Column1 Then 1
When Column0 = Column2 Then 1
When Column0 = Column3 Then 1
When Column0 = Column4 Then 1
When Column0 = Column5 Then 1
When Column0 = Column1 + Column2 Then 1
When Column0 = Column1 + Column3 Then 1
When Column0 = Column1 + Column4 Then 1
When Column0 = Column1 + Column5 Then 1
When Column0 = Column2 + Column3 Then 1
When Column0 = Column2 + Column4 Then 1
When Column0 = Column2 + Column5 Then 1
When Column0 = Column3 + Column4 Then 1
When Column0 = Column3 + Column5 Then 1
When Column0 = Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 Then 1
When Column0 = Column1 + Column2 + Column4 Then 1
When Column0 = Column1 + Column2 + Column5 Then 1
When Column0 = Column1 + Column3 + Column4 Then 1
When Column0 = Column1 + Column3 + Column5 Then 1
When Column0 = Column1 + Column4 + Column5 Then 1
When Column0 = Column2 + Column3 + Column4 Then 1
When Column0 = Column2 + Column3 + Column5 Then 1
When Column0 = Column2 + Column4 + Column5 Then 1
When Column0 = Column3 + Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 + Column4 Then 1
When Column0 = Column1 + Column2 + Column3 + Column5 Then 1
When Column0 = Column1 + Column3 + Column4 + Column5 Then 1
When Column0 = Column2 + Column3 + Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 + Column4 + Column5 Then 1
Else 0
End As SumOfOtherColumns
From YourTable
Even if the answer has already been accepted, here is my alternative solution. It is, most probably way worse in terms of performance ( to be tested ) But I thought it was worth showing for the following reasons :
As you can see, with 5 columns it's already easy to miss some cases and there are only 31 cases to check. this goes to 63checks if you add a column, 127 for the next one ... you dont have to worry about that here because it will generate all the cases dynamically
The other interesting point is that, if you are interested in seeing the detail of each row and why it matched, it comes free with the query. you just have to select the subview
The last point is, I think it's academically interesting. The solution contains UNPIVOTing the data, self joining recursively, on the fly dynamic expression evaluation. Well of course, i'm not objective but hell that was fun to do :)
--Table and data to test the query
create table my_table ( column0 number, column1 number, column2 number,
column3 number, column4 number, column5 number );
INSERT INTO my_table values (100,20,20,10,40,10); -- must match on the sum of 5 columns
INSERT INTO my_table values (100,50,200,300,150,250); -- must not match
INSERT INTO my_table values (100,50,50,100,150,250); -- must match twice ( on col1+col2 and col3 )
-- If your table has a unique key, you can remove the datas_with_id and put
-- your table directly in the unpivoted_data subquery
with datas_with_id as ( select rowid as row_id, t.* from my_table t),
unpivoted_data as ( select row_id, column0 as sum_to_check, column_name, column_value
from datas_with_id
unpivot ( column_value for column_name in (column1,column2,column3,column4,column5))),
calculated_sum as ( select row_id, xmlquery(sys_connect_by_path(u.column_value,'+')||' = '|| sum_to_check
returning content).getStringVal() result
from unpivoted_data u connect by nocycle prior column_name>column_name
and prior row_id=row_id and level < 6)
select * from my_table where rowid in ( select row_id from calculated_sum where result = 'true' )
If you want to add another column, add it in the unpivot clause, add 1 to the level and you are good
and if you add sys_connect_by_path(u.column_name,'+')||' = '|| sum_to_check in the calculated_sum, you can see every formula that matched
Here I wrote some codes that you can use it dynamically
1-Firstly I create table and generate one row for it
create table my_table ( column0 number, column1 number, column2 number,
column3 number, column4 number, column5 number );
INSERT INTO my_table values (100,20,20,10,40,10);
2-create type as following lines
create or replace type Key_Value_Typ as object
(
column_name varchar2(100),
column_val varchar2(100)
)
3-you can see an example here
declare
lv_count number;
lv_row my_table%rowtype;
type my_list is table of Key_Value_Typ;
list1 my_list;
------------------------------------------------------------
-- function for control column condition
function check_fun(
lv_list my_list,
-- the function input is array of key value include column name and column value
-- you can implement your code here, for example as input parameter declare your own parameters
-- for example
-- lv_column0 my_table.column0%type;
lv_where varchar2
-- the condition that you want check it
) return number is
lv_str varchar2(200);
lv_count number;
begin
lv_str := lv_where;
for i in 1 .. lv_list.count Loop
lv_str := replace(lv_str,
lv_list(i).column_name,
lv_list(i).column_val);
ENd Loop;
execute immediate 'select count(*) from dual where ' || lv_str
into lv_count;
-- if the function return 1 result is true and o means result is false
return lv_count;
end check_fun;
------------------------------------------------------------
begin
-- fetch data from my_table and get one of them
select * into lv_row from my_table where column0 = 100;
-- create list of data include columns and values
list1 := my_list(Key_Value_Typ('column0', lv_row.column0),
Key_Value_Typ('column1', lv_row.column1),
Key_Value_Typ('column2', lv_row.column2),
Key_Value_Typ('column3', lv_row.column3),
Key_Value_Typ('column4', lv_row.column4),
Key_Value_Typ('column5', lv_row.column5));
lv_count := check_fun(list1, 'column0=column1+column2+column3+column4+column5');
dbms_output.put_line('result ()' || lv_count);
end;

Compare 2 different string columns in an SQL database

I have two different columns of strings and I want to check if one is contained in the other and create a third column which has values of either 1 or 0( 1 if column2 contains column 1 and 0 if otherwise)
For example:
Column1 Column2 Column3
Spar I am Sparta 1
How are you Sparta 0
How do you do this string comparison in SQL ?
You could use the charindex function. Assuming you just want to check if colum1 is contained in column2:
SELECT CASE WHEN CHARINDEX(column1, column2) > 0
THEN 1
ELSE 0
END AS column3
FROM mytable
If you need to check both ways, just add another call:
SELECT CASE WHEN CHARINDEX(column1, column2) > 0 OR
CHARINDEX(column2, column1) > 0
THEN 1
ELSE 0
END AS column3
FROM mytable
Try this:
WITH temp(col1, col2) AS(
SELECT 'Spar', 'I am Sparta' UNION ALL
SELECT 'How are you', 'Sparta'
)
SELECT
*,
col3 =
CASE
WHEN col1 like '%' + col2 + '%' or col2 like '%' + col1 + '%' THEN 1
ELSE 0
END
FROM temp
It should work
select column1,column2, (case when column2 like '%' + column1 + '%' then 1 else 0 end) as column3 FROM yourtable
Try this
DECLARE #table1 TABLE
(
Column1 VARCHAR(20),
Column2 VARCHAR(20)
)
INSERT INTO #table1
VALUES ('Spar',
'I am Sparta'),
('How are you',
'Sparta')
SELECT column1,
column2,
CASE
WHEN CHARINDEX(column1, column2) > 0
OR CHARINDEX(column1, column2) > 0 THEN 1
ELSE 0
END AS column3
FROM #table1

Update column if another column contains a string

I have a table that contains three columns.
column1 column2 column3
mytestdata test
myotherdata test
I want to insert 'somestring' into column3 if column1 contains the value in column2
The result would look like:
column1 column2 column3
mytestdata test 'somestring'
myotherdata test
SQL Server:
UPDATE myTable
SET column3 = 'somestring'
WHERE column1 LIKE '%' + column2 + '%'
SQL Server:
UPDATE theTable SET column3 = 'somestring'
WHERE CHARINDEX (column2, column1) > 0
You have several options, depending on the RDBMS.
For both MySQL and Oracle:
UPDATE yourTable
set column3 = 'somestring'
where INSTR(column2, column1) > 0
For SQL Server:
UPDATE yourTable
set column3 = 'somestring'
where CHARINDEX(column1, column2) > 0
You could do something like below
UPDATE tmp
SET
column3 = (CASE WHEN tmp.column1 like '%' + tmp.column2 + '%' THEN 'something' ELSE tmp.column3')
FROM
tablename tmp