More efficient way to assign values to a column in SQL Server 2008 based on other column values - sql

I have a table with 5 columns like:
id value1 value2 value3 Score
1 X X X
2 X Y Z
3 Y Z Z
4 X Z X
What I want is to assign final values equal to Ys and Zs (not X) for each column like:
id value1 value2 value3 final
1 X X X 0
2 X Y Z 2
3 Y Z Z 3
4 X Z X 1
The way I am doing it is:
Update table
set final = 3
where value1 <> 'X' and value2 <> 'X' and value3 <> 'X'
Update table
set final = 2
where (value1 <> 'X' and value2 <> 'X' and value3 = 'X')
OR (value1 = 'X' and value2 <> 'X' and value3 <> 'X')
OR (value1 <> 'X' and value2 = 'X' and value3 <> 'X')
Update table
set final = 1
where (value1 <> 'X' and value2 = 'X' and value3 = 'X')
OR (value1 = 'X' and value2 <> 'X' and value3 = 'X')
OR (value1 = 'X' and value2 = 'X' and value3 <> 'X')
Update table
set final = 0
where value1 = 'X' and value2 = 'X' and value3 = 'X'
I would like to ask if there is any smarter/more efficient way rather than this? Any advice would be appreciated. Thanks!

Is this what you want?
Update table
set final = ((case when value1 <> 'X' then 1 else 0 end) +
(case when value2 <> 'X' then 1 else 0 end) +
(case when value3 <> 'X' then 1 else 0 end)
);
This counts the number of values that are not X.
Here is another method:
Update table
set final = len(replace(value1 + value2 + value3, 'X', '');
Note: This only works if the columns really do have values that have only one character.

use CASE WHEN . . .
Update table
set final = CASE WHEN value1<>'X' and value2<>'X' and value3<>'X' THEN 3
WHEN (value1<>'X' and value2<>'X' and value3='X')
OR (value1='X' and value2<>'X' and value3<>'X')
OR (value1<>'X' and value2='X' and value3<>'X') THEN 2
WHEN (value1<>'X' and value2='X' and value3='X')
OR (value1='X' and value2<>'X' and value3='X')
OR (value1='X' and value2='X' and value3<>'X') THEN 1
WHEN value1='X' and value2='X' and value3='X' THEN 0
END

Using Computed column. Correct me if desired output is not obtained.
CREATE TABLE GRADES (
id INT
,VALUE1 VARCHAR(10)
,VALUE2 VARCHAR(10)
,VALUE3 VARCHAR(10)
,final INT AS (
(
CASE
WHEN value1 <> 'X'
THEN 1
ELSE 0
END
) + (
CASE
WHEN value2 <> 'X'
THEN 1
ELSE 0
END
) + (
CASE
WHEN value3 <> 'X'
THEN 1
ELSE 0
END
)
)
);

create TRIGGER test
ON [dbo].[YourTable]
AFTER INSERT
AS
BEGIN
declare #Id int
declare #value1 nvarchar(10)
declare #value2 nvarchar(10)
declare #value3 nvarchar(10)
declare #Count int =0
select top(1) #Id=id, #value1=[m1] ,#value2=[m2],#value3=[m3] from [dbo].[Table_3] order by id DESC
if #value1='x'
begin
set #Count=#Count+1
end
if #value2='x'
begin
set #Count=#Count+1
end
if #value3='x'
begin
set #Count=#Count+1
end
update [dbo].[Table_3]
set Score=#Count
where id =#Id
END

Related

Two select statement with case

I have two queries and I have a value if value is 1 then first query will execute if value is 2 then second. How can i achieve this, my query is
Query one if value is 1
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END )AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS VARCHAR(10)) + ' / 1' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS "matches" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END )
)
Query 2 if value 2
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END
)AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END
+ CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS VARCHAR(10)) + '/ 2' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS "NUM_OF_MATCHES" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END+
CASE WHEN col2 = 10 THEN 1 ELSE 0 END )
I have try it using case but it is not working
I want if value = 1 then first query will run and if value = 2 then second
although both queries doing same work but if value is 1 then col1 logic will take only col1 and if value is 2 then it will take col1 and col2 if value is 3 then it will take col1 col2 and col3 till 6 col
You can make use of a simple if else if and execute both the queries.
IF(#value=1)
BEGIN
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END )AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS VARCHAR(10)) + ' / 1' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END AS "matches" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END )
)
END
ELSE IF(#value=2)
BEGIN
SELECT count (CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END
)AS "matches" ,
CAST( CASE WHEN col1 = 9 THEN 1 ELSE 0 END
+ CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS VARCHAR(10)) + '/ 2' AS "match by"
FrOM table a
where ( SELECT CASE WHEN col1 = 9 THEN 1 ELSE 0 END +
CASE WHEN col2 = 10 THEN 1 ELSE 0 END AS "NUM_OF_MATCHES" ) >= 1
group by ( CASE WHEN col1 = 9 THEN 1 ELSE 0 END+
CASE WHEN col2 = 10 THEN 1 ELSE 0 END )
END
still are you using CASE Statement, why dont you try to use IIF Statement, IIF Statement is more efficient and fast compare to CASE Statement.
e.g.
select IIF(1=1, (your desired column1),(your desired column2)) as matches
you can also use nested IIF Statement in single query like CASE Statement..
select IIF(1=1, (IIF(2=2, (your desired column1),(your desired column2))),(your desired column3)) as matches.

How to deal with duplicate rows in SQL?

The table has duplicate IDs from a large table. I want to get one output for each ID. What's the best way to do it?
MyTable
ID Col1 Col2
1 X A
1 Y B
1 Z C
2 X D
2 Y E
3 Z F
3 W G
If Col1 = 'X' and Col2 ='A', then 'Y' is the output for ID1
If Col1 = 'X' and Col2 !='A', then 'N' is the output for ID2
If Col1 != 'X', then 'Y' is the output for ID3
If Col1 = 'X' and Col2 ='A', then 'Y' is the output for ID1
If Col1 = 'X' and Col2 !='A', then 'N' is the output for ID2
If Col1 != 'X', then 'Y' is the output for ID3
I assume the conditions above need to be true for only 1 row per id. You can use conditional aggregation to check whether the condition applies to at least 1 row per group:
select id,
case when count(case when Col1 = 'X' and Col2 = 'A' then 1 end) > 0 then 'Y'
when count(case when Col1 = 'X' and Col2 <> 'A' then 1 end) > 0 then 'N'
when count(case when Col1 = 'X' then 1 end) > 0 then 'Y'
else '?'
end as output
from mytable
group by id

SQL Server Sum rows with string value

I have a dynamic SQL query which returns rows like below with string values & numeric values.
EMP col1 col2 col3 col4 col5
----------------------------
A1 4 4 3 3 3
A2 4 2 5 3 3
A3 sd 3 3 1 sd
A4 3 4 3 3 3
Now I need a new column which sums col1 to col5 and creates a total sum column where it should ignore the string values as in row 3. There are no NULL values
How could I achieve this? Using ISNUMERIC might be the solution, but I'm not sure how to use it in such a scenario.
You can use a CASE Expression to determine whether the value is a number. If it is a number then either cast the value to an INT or DECIMAL data type, otherwise use 0 so it doesn't effect the sum.
SELECT
CASE WHEN ISNUMERIC(col1) = 1 THEN CAST(col1 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col2) = 1 THEN CAST(col2 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col3) = 1 THEN CAST(col3 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col4) = 1 THEN CAST(col4 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col5) = 1 THEN CAST(col5 as INT) ELSE 0 END as SumValue
FROM MyTable
If you're on SQL Server 2012, TRY_CONVERT avoids pitfalls commonly encountered with ISNUMERIC:
SELECT col1, col2, col3, col4, col5,
ISNULL(TRY_CONVERT(int, col1), 0) +
ISNULL(TRY_CONVERT(int, col2), 0) +
ISNULL(TRY_CONVERT(int, col3), 0) +
ISNULL(TRY_CONVERT(int, col4), 0) +
ISNULL(TRY_CONVERT(int, col5), 0) AS total
FROM Employee
SQLFiddle
You can do this with a big case statement:
select q.*,
((case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
(case when isnumeric(col2) = 1 then cast(col2 as int) else 0 end) +
(case when isnumeric(col3) = 1 then cast(col3 as int) else 0 end) +
(case when isnumeric(col4) = 1 then cast(col4 as int) else 0 end) +
(case when isnumeric(col5) = 1 then cast(col5 as int) else 0 end)
) as newcol
from q;
isnumeric() should be sufficient for your purposes. You might need fancier logic if you only want positive integers or want to exclude exponential notations or the like.
You're on the right track with isnumeric:
select
emp,
(case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
col2...
from table1

SQL code (SSRS 2008 version)

I need to write the following in SQL:
I have a table that has 2 columns that I am interested in (ID, Text field). Each ID could have a few values in the text field.
ID TEXT
1 value1
1 value2
2 value1
2 value2
2 value4
I need to create a report that list the following
ID value1 value2 value3 value4 etc.
1 yes yes
2 yes yes yes
thank you
SELECT
ID,
Value1 = MAX(case WHEN [Text] = 'Value1' THEN 'yes' ELSE '' END),
Value2 = MAX(case when [Text] = 'Value2' THEN 'yes' ELSE '' END),
Value3 = MAX(case when [Text] = 'Value3' Then 'yes' ELSE '' END)
GROUP BY
ID

Pivot / unpivot in SQL

I have a view in SQL that I have generated by analysing the values in tables so that field either contain the value 'N', 'D' or 'V'. I can work out the totals by column but not by row... Is this possible?
Example:
Data
No, Col_1, Col_2, Col_3
1, N, N, N
2, N, D, D
3, N, V, D
4, V, V, V
How do I summise that Row 3 has 1N, 1V and 3ds whilst Row 4 has 4Vs?
Bet is quite simple but sadly so am I!
Many thanks in advance,
Peter
select case when col_1 = 'N' then 1 else 0 end as n_count from tablename;
Generalizing that:
select
case when col_1 = 'N' then 1 else 0 end
+ case when col_2 = 'N' then 1 else 0 end
+ case when col_2 = 'N' then 1 else 0 end as n_count,
case when col_1 = 'V' then 1 else 0 end
+ case when col_2 = 'V' then 1 else 0 end
+ case when col_2 = 'V' then 1 else 0 end as v_count,
....
from tablename;
How about?
select no,
sum(case when val = 'N' then 1 else 0 end) ncnt,
sum(case when val = 'V' then 1 else 0 end) vcnt,
sum(case when val = 'D' then 1 else 0 end) dcnt from
(select no, col_1 val from t union all
select no, col_2 from t union all
select no, col_3 from t)
group by no
order by no