Create a new column based on existing columns inside a case statement - sql

Say I have this table t:
id value
1 1 10
2 2 3
3 1 55
4 1 20
5 2 98
When drawing from t I want to add a column value2 that equals value when id == 2, otherwise 0
I tried
select id, value, max(case when id = 2 then value else 0) from t
but it did not work

Not sure why you included a max in your attempt but based on your description, this is all you should need.
select id, value, case when id = 2 then value else 0 end as value2
from t;

It sounds like you want a conditional window aggregate:
select
id,
value,
max(case when id = 2 then value end) over ()
from t;

Related

SQL select rows into new columns

I have a database table which looks like this:
ID parameter value
1 A 1
1 B 1002
2 A 5
2 B 1055
I would like to create a SQL query to receive such a table:
ID value of parameter A value of parameter B
1 1 1002
2 5 1055
How can I transform the table to create a new columns for each parameter with it corresponding value?
You can combine CASE with any aggregation function (like SUM(), MAX(), etc.) to pivot the data manually.
For example:
select
id,
sum(case when parameter = 'A' then value end) as a,
sum(case when parameter = 'B' then value end) as b,
...
sum(case when parameter = 'Z' then value end) as z
from t
group by id

How i want make 3 rows of the same primary key into 1 row by checking and choose its value using case

For example here, from this table
key | status
1001 | A
1001 | D
1001 | C
the hierarchy will be C>D>A
If the the stats contain C as the value, the person status will become C in one row. It will be like this:
key | status
1001 | C
it will ignore D and A because it has value C. If it doesn't has C,then it will check for D first before A.
So, how can i do that? I dont how to make the 3 row into 1. I tried using
''' CASE WHEN STATUS IN('C')THEN 'C'
ELSE WHEN STATUS IN('D') THEN 'D'
ELSE WHEN STATUS IN('A') THEN 'A'
END AS STATUS '''
But it give error and still can't make the row into 1
You can try the below -
select key, status
from tablname
order by case when status='C' then 1 when status='D' then 2 when status='A' then 3 else 99 end
FETCH FIRST 1 ROW
You can use analytical function row_number as follows:
Select * from
(Select t.*,
Row_number() over (partition by key order by case when status = 'C' then 1
when status = 'D' then 2
when status = 'A' then 3 end) as rn
From your_table)
Where rn = 1;

Updating Rows in a normalized table

normalized table
ID SEQ Type Value Flag
1 1 a 100 -
1 2 a 200 -
1 3 a 250 -
1 4 b 200 -
2 1 a 150 -
2 2 b 100 -
2 3 b 200 -
How do I write a single update statement such that the resulting table is populated as follows
ID SEQ Type Value Flag
1 1 a 100 valid
1 2 a 200 repeat
1 3 a 250 repeat
1 4 b 200 valid
2 1 a 150 valid
2 2 b 100 valid
2 3 b 200 repeat
Edit: included seq column
only the first occurence of the value for a type for a ID group should have the valid flag
should it be written as two separate update statements?
can someone clarify me?
Much appreciated
Populate the table first using row_number() and then update the table.
Option 1:
select
Id,
Type,
Value,
null as Flag,
row_number() over (partition by ID, Type order by SEQ) as rnk
from yourTable
then you can use update
update yourTable
set flag = case
when rnk = 1 then 'valid'
else 'repeat'
end
Option 2:
You may be able to do without using update statement as following
select
Id,
SEQ,
Type,
Value,
case
when rnk = 1 then 'valid'
else 'repeat'
end as flag
from
(
select
Id,
SEQ,
Type,
Value,
row_number() over (partition by ID, Type order by SEQ) as rnk
from yourTable
) val

One column condition in sql

I have a table:
[letter] [Name] [status] [price]
A row1 1 11
A row1 1 15
B row2 2 9
B row2 3 23
B row2 3 30
And want to select data something like this:
SELECT letter, Name,
COUNT(*),
CASE WHEN price>10 THEN COUNT(*) ELSE NULL END
GROUP BY letter, Name
the result is:
A row1 2 2
B row2 1 null
B row2 2 2
But I want this format:
A row1 2 2
B row2 3 2
Please, help me to modify my query
Close. Probably want this instead:
SELECT letter, Name,
COUNT(*),
SUM(CASE WHEN price>10 THEN 1 ELSE 0 END)
FROM TableThatShouldHaveAppearedInTheQuestionInTheFromClause
GROUP BY letter, Name
should work. Assuming that the intention of the fourth column is to return the count of the number of rows, within each group, with a price greater than 10. It's also possible to do this as a COUNT() over a CASE then returns non-NULL and NULL results for the rows that should and should not be counted, but I find the above form easier to quickly reason about.
Since nulls are not used in aggregate functions:
SELECT letter
, name
, count(*)
, count(
case when price > 10 then 1
end
)
FROM t
GROUP BY letter, name
You were very close.
Looking to the other answers, probably this is not the best way, but it will work.
The count of the prices over 10 is made with a subquery which has a condition on price > 10 and which is joined to the current TAB record with the alias A for the same letter and name.
SELECT letter,
Name,
COUNT(*),
(SELECT COUNT(*) FROM TAB WHERE letter = A.letter and Name = A.Name WHERE price>10)
FROM TAB A
GROUP BY letter, Name

SQL Server Conditional filtering

I essentially would like to execute a statement where x=1 AND a=2. If a<>2 then return results for filter x=1.
I've tried OR statement but it ignores my a=2 filter if there is a scenario where a does equal 2. Example below
select *
from dbo.test
where (x=1 and a=2)
or
x=1
For output purposes below: type = x and Id = a
Expected result when Type = 1.
Id(a) Name Person Type(x)
2 a Mike 1
7 b Jim 1
3 c Tom 1
4 d Tim 1
5 e Dave 1
Expected result when Type = 1 and Id = 2
Id(a) Name Person Type(x)
2 a Mike 1
Expected result when Type = 1 and Id <> 2 (scenario when there is no '2' in Id column)
Id(a) Name Person Type(x)
8 a Mike 1
7 b Jim 1
3 c Tom 1
4 d Tim 1
5 e Dave 1
The issue is not when Id = 2. It is returning Type = 1 when Id <> 2. Does that mean a case statement?
select *
from dbo.test
where (x=1 and a=2)
or x=1
Is the same as:
select *
from dbo.test
where x=1
AND requires both conditions be met, and OR requires one condition to be met. The value of a is irrelevant.
UPDATE:
You can get what you're after using the RANK() function in conjunction with a CASE statement:
;WITH cte AS (SELECT *,RANK() OVER(ORDER BY CASE WHEN id = 2 THEN 1 ELSE 2 END)RNK
FROM Table1
WHERE Type = 1)
SELECT *
FROM cte
WHERE RNK = 1
If id = 2 is present in the table, only that record will be returned, otherwise all records will be returned.
Demo: SQL Fiddle
I'm guessing that you want to return a single row.
insert into test(x,a,v) values (0, 0, 'No good')
insert into test(x,a,v) values (1, 0, 'OK')
insert into test(x,a,v) values (1, 2, 'Better')
You want the row that has x=1 a=2 if it is there
You want the row that has x=1 if there is none better
You want nothing if there is no x=1 row
If that's the case then it is a bit tricky. You can score the rows using a CASE statement and then pick the row that has the best value. This may give you more than one row back if there is a tie.
SELECT v
FROM test
WHERE CASE WHEN x=1 AND a=2 THEN 1000
WHEN x=1 AND a<>2 THEN 100
ELSE 0 END =
(SELECT MAX(CASE WHEN x=1 AND a=2 THEN 1000
WHEN x=1 AND a<>2 THEN 100
ELSE 0 END)
FROM test)