I need a SQL query having WHERE CASE WHEN statement with a in list. I am not sure what part of my query is wrong,
First I need to make a KEY out of coldelist and IDD,IDP and then since my codelists' lenght are 5 or 6 so need to use CASE WHEN to check if their length are 5 or 6 then search in separate lists (each almost 200 or more) because my aim is to compare some tables' data using EXCEPT
My SQL statement is like:
SELECT
codelist = CASE
WHEN LEN(codelist) = 5
THEN CONCAT(CONCAT(SUBSTRING(codelist, 1, 5), IDD), IDP)
WHEN LEN(codelist) = 6
THEN CONCAT(CONCAT(SUBSTRING(codelist, 1, 6), IDD), IDP)
ELSE codelist
END,
codelist
FROM
[table1]
WHERE
(codelist = CASE
WHEN LEN(codelist) = 5
THEN (SELECT 'FEV00', 'FEV64', 'FEV97', 'FEV90')
WHEN LEN(codelist) = 6
THEN (SELECT 'FEV208', 'FEV227', 'FEV308', 'FEV326')
END)
EXCEPT
SELECT
....
Related
I use a case when it works perfectly fine on MySQL but not MS SQL please help.
It seems the equal is not accepted -- if not what then will work
SELECT A FROM TABLE A
WHERE
CASE WHEN COUNT = 2 THEN GOAL = 2 ELSE GOAL = 3 END
Msg 156, Level 15, State 1, Line 3 Incorrect syntax near the keyword
'CASE'.
You need to change your query to WHERE columnName = value.
The following query is what you are expecting:
SELECT A.*
FROM TABLE A
WHERE GOAL = CASE WHEN COUNT = 2 THEN 2 ELSE 3 END
How do I go about writing a query where I want to get the last value?
For example I have a table with with tasks, 1-4 for each parent workflow.
I then have a completed column with a 1 or 0.
I would like to return 1 value, Task 1 or 2 or 3 or 4 depending if the task is complete.
I tried an embedded CASE statement, but it would always returns value 4.
There has to be a better way.
SELECT
Estimate.EstimateID, Estimate.EstimateNo,
CASE
WHEN TransWorkFlow.OwnerID = Estimate.EstimateID
THEN
CASE
WHEN TransWorkFlowDetails.TaskNo = 1 AND TransWorkFlowDetails.Completed = 0
THEN 1
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 2 AND TransWorkFlowDetails.Completed = 0
THEN 2
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 3 AND TransWorkFlowDetails.Completed = 0
THEN 3
ELSE
CASE
WHEN TransWorkFlowDetails.TaskNo = 4 AND TransWorkFlowDetails.Completed = 0
THEN 4
ELSE 4
END
END
END
END
END AS TaskCompleted
FROM
TransWorkFlow
INNER JOIN
TransWorkFlowDetails ON TransWorkFlow.TransWorkFlowID = TransWorkFlowDetails.TransWorkFlowID
INNER JOIN
Estimate ON TransWorkFlow.OwnerID = Estimate.EstimateID
It seems like this can be simplified into one simple CASE statement
SELECT
e.EstimateID,
e.EstimateNo,
CASE WHEN td.Completed = 0 AND td.TaskNo IN (1,2,3,4) THEN td.TaskNo ELSE 4 END AS TaskCompleted
FROM TransWorkFlow t
INNER JOIN TransWorkFlowDetails td ON t.TransWorkFlowID = td.TransWorkFlowID
INNER JOIN Estimate e ON t.OwnerID = e.EstimateID;
Note:
we're using aliases like t, td and e to shorten the code
we got rid of your initial CASE check, because it's covered by the INNER JOIN
TaskNo seems to be your check condition and also output, let's can reference that in THEN part
Not really clear what you are trying to do here but I think that wall of case expressions could be simplified to this.
case when TransWorkFlowDetails.Completed = 0
AND TransWorkFlowDetails.TaskNo in (1, 2, 3, 4)
THEN TransWorkFlowDetails.TaskNo
ELSE
--whatever you want here
END
I have a data like below.
id col1[]
--- ------
1 {1,2,3}
2 {3,4,5}
My question is how to use replace function in arrays.
select array_replace(col1, 1, 100) where id = 1;
but it gives an error like:
function array_replace(integer[], integer, integer) does not exist
can anyone suggest how to use it?
Your statement (augmented with the missing FROM clause):
SELECT array_replace(col1, 1, 100) FROM tbl WHERE id = 1;
As commented by #mu, array_replace() was introduced with pg 9.3. I see 3 options for older versions:
1. intarray
As long as ...
we are dealing with integer arrays.
elements are unique.
and the order of elements is irrelevant.
A simple and fast option would be to install the additional module intarray, which (among other things) provides operators to subtract and add elements (or whole arrays) from/to integer arrays:
SELECT CASE col1 && '{1}'::int[] THEN (col1 - 1) + 100 ELSE col1 END AS col1
FROM tbl WHERE id = 1;
2. Emulate with SQL functions
A (slower) drop-in replacement for array_replace() using polymorphic types, so it works for any base type:
CREATE OR REPLACE FUNCTION f_array_replace(anyarray, anyelement, anyelement)
RETURNS anyarray LANGUAGE SQL IMMUTABLE AS
'SELECT ARRAY (SELECT CASE WHEN x = $2 THEN $3 ELSE x END FROM unnest($1) x)';
Does not replace NULL values. Related:
Replace NULL values in an array in PostgreSQL
If you need to guarantee order of elements:
PostgreSQL unnest() with element number
3. Apply patch to source and recompile
Get the patch "Add array_remove() and array_replace() functions" from the git repo, apply it to the source of your version and recompile. May or may not apply cleanly. The older your version the worse are your chances. I have not tried that, I would rather upgrade to the current version.
You can create your own
based on this source :
CREATE TABLE arr(id int, col1 int[]);
INSERT INTO arr VALUES (1, '{1,2,3}');
INSERT INTO arr VALUES (2, '{3,4,5}');
SELECT array(
SELECT CASE WHEN q = 1 THEN 100 ELSE q END
FROM UNNEST(col1::int[]) q)
FROM arr;
array
-----------
{100,2,3}
{3,4,5}
You can create your own function and put it in your public schema if you still want to call by function though it will be slightly different than the original.
UPDATE tbl SET col1 = array_replace(col1, 1, 100) WHERE id = 1;
Here is the sample query for a test-array:
SELECT test_id,
test_array,
(array (
-- Replace existing value 'int' of an array with given value 'Text'
SELECT CASE WHEN a = '0' THEN 'MyEntry'
WHEN a = '1' THEN 'Apple'
WHEN a = '2' THEN 'Banana'
WHEN a = '3' THEN 'ChErRiEs'
WHEN a = '4' THEN 'Dragon Fruit'
WHEN a = '5' THEN 'Eat a Fruit in a Day'
ELSE 'NONE' END
FROM UNNEST(test_array::TEXT[]) a) ::TEXT
-- UNNEST : Lists out values of my_test_array
) test_result
FROM (
--my_test_array
SELECT 1 test_id, '{0,1,2,3,4,5,6,7,8,9}'::TEXT[][] test_array
) test;
I have a query analogous to:
update x
set x.y = (
select sum(x2.y)
from mytable x2
where x2.y < x.y
)
from mytable x
the point being, I'm iterating over rows and updating a field based on a subquery over those fields which are changing.
What I'm seeing is the subquery is being executed for each row before any updates occur, so the changed values for each row are not being picked up.
How can I force the subquery to be re-evaluated for each row of the update?
Is there a suitable table hint or something?
As an aside, I was doing the below and it did work, however since modifying my query somewhat (for logic purposes, not to try and solve this issue) this trick no longer works :(
declare #temp int
update x
set #temp = (
select sum(x2.y)
from mytable x2
where x2.y < x.y
),
x.y = #temp
from mytable x
I'm not particularly concerned about performance, this is a background task run over a few rows
It looks like task is incorrect or other rules should apply.
Let's see on example. Let's say you have values 4, 1, 2, 3, 1, 2
Sql will update rows based on original values. I.e. during single update statement newly calculated values is NOT mixing with original values:
-- only original values used
4 -> 9 (1+2+3+1+2)
1 -> null
2 -> 2 (1+1)
3 -> 6 (1+2+1+2)
1 -> null
2 -> 2 (1+1)
Based on your request you wants that update of each rows will count newly calculated values. (Note, that SQL does not guarantees the sequence in which rows will be processed.)
Let's do this calculation by processing rows from top to bottom:
-- from top
4 -> 9 (1+2+3+1+2)
1 -> null
2 -> 1 (1)
3 -> 4 (1+1+2)
1 -> null
2 -> 1 (1)
Do the same in other sequence - from bottom to top:
-- from bottom
4 -> 3 (2+1)
1 -> null
2 -> 1 (1)
3 -> 5 (2+2+1)
1 -> null
2 -> 2 (1+1)
How you can see your expected result is inconsistent. To make it right you need to correct the calculation rule - for instance define strong sequence of the rows to process (date, id, ...)
Also, if you want to do some recursive processing look at the common_table_expression:
http://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
I have a query that outputs some rows that I need to "filter".
The data I want to filter is like this:
rownum value
1 0
2 0
3 1
4 1
I need the first 2 rows, but only when they have "0" in the value-column.
The structure of the query is like this:
select count(x)
from
(
select row_number() over (partition by X order by y) as rownum, bla, bla
from [bla bla]
group by [bla bla]
) as temp
where
/* now this is where i want the magic to happen */
temp.rownum = 1 AND temp.value = 0
AND
temp.rownum = 2 AND temp.value = 0
So I want x only when row 1 and 2 have "0" in the value-column.
If either rownumber 1 or 2 have a "1" in the value-column, I dont want them.
I basically wrote the where-clause the way I wrote it here, but it's returning data sets that have "1" as value in either row 1 or 2.
How to fix this?
A value in a single row for a given column can never be both 1 and 2 at the same time.
So, first of all, either use OR (which is what I believe you intended):
WHERE (temp.rownum = 1 AND temp.value = 0)
OR (temp.rownum = 2 AND temp.value = 0)
Or simplify the query altogether:
WHERE temp.rownum <= 2 AND temp.value = 0
From here, you will get just the first two rows, and only if value = 0. If you only want rows when both rows are returned (i.e. both rows have value = 0), add
HAVING COUNT(1) = 2
to the query.