Here is my test T-SQL.
DECLARE #TestVal INT
SET #TestVal = 1
SELECT
CASE #TestVal
WHEN (1 | 2 | 6) THEN 'First' // I would like to check 1 or 2 or 6.
WHEN 3 THEN 'Second'
WHEN 4 THEN 'Third'
ELSE 'Other'
END
The current result is 'Other'.
I would like to get the result as 'First'. How can I use (OR statement) in my T-SQL.
Best regards
Use the condition form of case:
SELECT (CASE WHEN #TestVal IN (1, 2, 6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END)
Try this instead:
SELECT
CASE WHEN #TestVal IN (1, 2, 6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END
Above answers are correct also you can use OR like this:
DECLARE #TestVal INT
SET #TestVal = 2
SELECT (CASE WHEN (#TestVal = 1 OR #TestVal=2 OR #TestVal=6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END)
Related
Say I create this table and an array of values:
names = {'a'; 'b'; 'c'; 'd'} ; values = {'1'; '2'; '3'; '4'};
originalTable = table(names, values, 'VariableNames', {'names', 'values'});
nRepeat = [10, 50, 100, 2] ;
I want to create a new table which will contain each row repeated the number of times of corresponding index of nRepeat, i.e. I would have the first row or the original table repeated 10 times, followed by the second row of the original table repeated 50 times, and so on...
In addition, I want to add a column to that new table with the index of the repetition.
What I did:
% Initialize newTable to allocate memory space
totalRepetitions = sum(nRepeat) ;
% Repeated first row of the original table the same number of times as the totalRepetitions that will happen, also adding the new column with the index of repetition
newTable = repmat([originalTable(1,:), array2table(1, 'VariableNames', {'idxRepetition'})], totalRepetitions , 1) ;
addedRows = 0 ;
for idxName = 1 : numel(originalTable.names)
newTable(addedRows +1 : addedRows + nRepeat(idxName) , :) =...
[repmat(originalTable(idxName ,:), nRepeat(idxName), 1), array2table( (1:1:nRepeat(idxName))', 'VariableNames', {'idxRepetition'}) ] ;
addedRows = addedRows + nRepeat(idxName);
end
This works, but it becomes painfully slow for large tables.
Is there a more efficient way to do this?
You can simply use repelem on the indexes:
indx = repelem((1:numel(nRepeat)),nRepeat);
idxrep = arrayfun(#(x) 1:1:x,nRepeat,'un',0)'
finalTable = [originalTable(indx, :), table([idxrep{:}]','VariableNames', {'idxRepetition'})];
finalTable:
162×3 table
names values idxRepetition
_____ ______ _____________
'a' '1' 1
'a' '1' 2
'a' '1' 3
'a' '1' 4
'a' '1' 5
'a' '1' 6
'a' '1' 7
'a' '1' 8
'a' '1' 9
'a' '1' 10
'b' '2' 1
'b' '2' 2
'b' '2' 3
How is this?
Irep = arrayfun(#(n) n*ones(1,nRepeat(n)), 1:length(nRepeat),'UniformOutput',false);
Irep = [Irep{:}]';
Iidx = arrayfun(#(n) 1:nRepeat(n), 1:length(nRepeat),'UniformOutput',false);
Iidx = [Iidx{:}]';
newTable = table(names(Irep),values(Irep), Iidx, 'VariableNames', {'names', 'values','idxRepetition'});
Outputs this:
newTable =
162×3 table
names values idxRepetition
_____ ______ _____________
'a' '1' 1
'a' '1' 2
'a' '1' 3
'a' '1' 4
'a' '1' 5
'a' '1' 6
'a' '1' 7
'a' '1' 8
'a' '1' 9
'a' '1' 10
'b' '2' 1
'b' '2' 2
'b' '2' 3
'b' '2' 4
'b' '2' 5
...
I ask if the nested houses are used as follows:
SELECT
CASE
WHEN Col1 < 2 THEN
CASE Col2
WHEN 'X' THEN 10
ELSE 11
END
WHEN Col1 = 2 THEN 2
.....
ELSE 0
END as Qty,
......,
FROM ....
explanation: If Col1 <2 shows something, but that something if X gives me the value 10 otherwise 11 If Col1 = 2 shows 2 otherwise 0 everything in the column name Qty
Is the reasoning correct?
Thanks in advance
It's should return what you say you need, but it's easier to read this way:
SELECT
CASE
WHEN Col1 < 2 AND Col2 = 'X' THEN 10
WHEN Col1 < 2 THEN 11
WHEN Col1 = 2 THEN 2
--.....
ELSE 0
END AS Qty
FROM
-- ...
I'm trying to format one SELECT statement so that it outputs a resultset with combined values over a few columns.
I have a resultset like this:
ID VID PID VALUE
1 x 1 a
2 y 1 A
3 y 2 B
4 x 2 b
5 y 3 C
6 x 3 c
7 x 4 d
8 y 4 D
9 x 5 e
10 y 5 E
Can I format one SELECT statement to effectively join the values with duplicate PIDs into a single row? I'm only really interested in PID and VALUE, e.g.
PID VALUE1 VALUE2
1 a A
2 b B
3 c C
4 d D
5 e E
Otherwise, should I be using actual JOINs with queries acting on the same table?
I tried to use CASE but can get up to a resultset like this:
ID VID PID VALUE1 VALUE2
1 x 1 a NULL
2 y 1 NULL A
3 y 2 NULL B
4 x 2 b NULL
5 y 3 NULL C
6 x 3 c NULL
7 x 4 d NULL
8 y 4 NULL D
9 x 5 e NULL
10 y 5 NULL E
The query I'm using looks somewhat like this.
SELECT
ID,
VID,
PID,
CASE WHEN VID = 'x' THEN VALUE END VALUE1,
CASE WHEN VID = 'y' THEN VALUE END VALUE2
FROM BIGTABLE
WHERE PID IN (1, 2, 3, 4, 5)
AND VID IN ('x', 'y')
There's a lot of values of PID and VID that aren't just 1-5 and x & y so I'm selecting them that way from the whole table.
Do you mean like this? It's called "conditional aggregation."
with
resultset ( id, vid, pid, value ) as (
select 1, 'x', 1, 'a' from dual union all
select 2, 'y', 1, 'A' from dual union all
select 3, 'y', 2, 'B' from dual union all
select 4, 'x', 2, 'b' from dual union all
select 5, 'y', 3, 'C' from dual union all
select 6, 'x', 3, 'c' from dual union all
select 7, 'x', 4, 'd' from dual union all
select 8, 'y', 4, 'D' from dual union all
select 9, 'x', 5, 'e' from dual union all
select 10, 'y', 5, 'E' from dual
)
-- End of simulated resultset (for testing purposes only, not part of the solution).
-- SQL query begins below this line.
select pid,
min(case when vid = 'x' then value end) as value1,
min(case when vid = 'y' then value end) as value2
from resultset
-- WHERE conditions, if any are needed - as in your attempt
group by pid
order by pid
;
PID VALUE1 VALUE2
--- ------ ------
1 a A
2 b B
3 c C
4 d D
5 e E
I'm trying to implement what I have in code as a postgres query.
The following example isn't exactly what we're trying to do but I hope it shows how I'm trying to use the value from a previously calculated row in the next.
A sample table to help me demonstrate what I'm trying to do :
test=# select * from test ;
id | field1 | field2 | field3 | score
----+--------+--------+--------+-------
1 | 1 | 3 | 2 | 1.25
2 | 1 | -1 | 1 |
3 | 2 | 1 | 5 |
4 | 3 | -2 | 4 |
Here's the query in progress:
select id,
coalesce (
score,
case when lag_field3 = 2 then 0.25*(3*field1+field2) end
) as new_score
from (
select id, field1, field2, field3, score,
lag (field3) over (order by id) as lag_field3
from test
) inner1 ;
Which returns what I want so far ...
id | new_score
----+-----------
1 | 1.25
2 | 0.5
3 |
4 |
The next iteration of the query:
select id,
coalesce (
score,
case when lag_field3 = 2 then 0.25*(3*field1+field2) end,
case when field1 = 2 then 0.75 * lag (new_score) end
) as new_score
from (
select id, field1, field2, field3, score,
lag (field3) over (order by id) as lag_field3
from test
) inner1 ;
The difference is this :
case when field1 = 2 then 0.75 * lag (new_score) end
I know and understand why this won't work.
I've aliased the calculated field as new_score and when field1 = 2, I want 0.75 * the previous rows new_score value.
I understand that new_score is an alias and can't be used.
Is there some way I can accomplish this? I could try to copy that expression, wrap a lag around it, alias that as something else and try to work with that but that would get very messy.
Any ideas?
Many thanks.
Postgres lets you use windows in CASE statements. Probably you were missing the OVER (ORDER BY id) part. You can also define different windows but you can't use windows in conjunction with GROUP BY. Also, it won't let you use annidate windows, so you have to write down some subqueries or CTEs.
Here's the query:
SELECT id, COALESCE(tmp_score,
CASE
WHEN field1 = 2
THEN 0.75 * LAG(tmp_score) OVER (ORDER BY id)
-- missing ELSE statement here
END
) AS new_score
FROM (
SELECT id, field1,
COALESCE (
score,
CASE
WHEN LAG(field3) OVER (ORDER BY id) = 2
THEN 0.25*(3*field1+field2)
END
) AS tmp_score
FROM test
) inner1
The code to create and populate the table:
CREATE TABLE test(
id int,
field1 int,
field2 int,
field3 int,
score numeric
);
INSERT INTO test VALUES
(1, 1, 3, 2, 1.25),
(2, 1, -1, 1, NULL),
(3, 2, 1, 5, NULL),
(4, 3, -2, 4, NULL);
The query returns this output:
id | new_score
----+-----------
1 | 1.25
2 | 0.50
3 | 0.3750
4 |
I have three variables :-
#ScoreA DECIMAL(10,7)
#ScoreB DECIMAL(10,7)
#ScoreC DECIMAL(10,7)
#FinalScore DECIMAL(10, 7)
I wish to get the average of the three scores. BUT 1, 2 or all 3 values might be zero.
Eg. scenarios:
A = 1.4, B=3.5, C=5.0; FinalScore = 3.3
A = 0.0, B=0.0, C=0.0; FinalScore = 0.0
A = 1.1, B=0.0, C=0.0; FinalScore = 1.1
A = 0.0, B=2.0, C=4.8; FinalScore = 3.4
Cheers!
IF #A > 0 OR #B > 0 OR #C > 0
SELECT ((#A + #B + #C) /
(0 +
CASE WHEN #A = 0 THEN 0 ELSE 1 END +
CASE WHEN #B = 0 THEN 0 ELSE 1 END +
CASE WHEN #C = 0 THEN 0 ELSE 1 END ))
ELSE
SELECT 0.0
EDIT
Modified query to now handle divide by zero scenario's.
EDIT2
Here is "the trick with the AVG(..) function" :) with Common Table Expression
WITH T(I) AS (SELECT #A UNION SELECT #B UNION SELECT #C)
SELECT AVG(I) FROM T
WHERE I > 0
SELECT ((#A + #B + #C) /
(CASE WHEN (#A = 0.0 AND #B = 0.0 AND #C = 0.0) THEN 1 ELSE 0 END
+ CASE WHEN #A = 0 THEN 0 ELSE 1 END
+ CASE WHEN #B = 0 THEN 0 ELSE 1 END
+ CASE WHEN #C = 0 THEN 0 ELSE 1 END
)
)
For me this is easier to read and understand:
DECLARE
#ScoreA DECIMAL(10,7),
#ScoreB DECIMAL(10,7),
#ScoreC DECIMAL(10,7),
#FinalScore DECIMAL(10, 7)
SET #ScoreA = 1.4
SET #ScoreB = 3.5
SET #ScoreC = 5.0
DECLARE
#AVG TABLE (value DECIMAL(10,7))
INSERT INTO #AVG
SELECT #ScoreA WHERE #ScoreA > 0
UNION
SELECT #ScoreB WHERE #ScoreB > 0
UNION
SELECT #ScoreC WHERE #ScoreC > 0
SELECT COALESCE(AVG(value), 0) FROM #AVG