Update Case When, with multiple conditions - mysql

I have this table:
CREATE TABLE IF NOT EXISTS `my_table` (
`A` int(11) NOT NULL,
`B` int(11) NOT NULL,
`C` varchar(50) NOT NULL,
`D` varchar(30) NOT NULL,
PRIMARY KEY (`A`,`B`,`C`)
)
I want to update several entries in just one query. I tried this:
UPDATE my_table
SET D = CASE
WHEN (A = 6 AND B = 1 AND C = 'red') THEN '1#2#3#5#4'
WHEN (A = 8 AND B = 1 AND C = 'green') THEN '5#6#7#8#9'
END
But this query updates all entries in the table. It updates perfectly the value of 'D' of the two entries I want to update, but it also deletes the values of "D" of the other entries, and I want them to stay with their previous values.

If you do not explicitly add an else clause to a case expression, it implicitly acts as though you've added else null to it. So, your update statement is effectively equivalent to:
UPDATE my_table
SET D = CASE
WHEN (A = 6 AND B = 1 AND C = 'red') THEN '1#2#3#5#4'
WHEN (A = 8 AND B = 1 AND C = 'green') THEN '5#6#7#8#9'
ELSE NULL
END
Which explains why you see D being "deleted".
One way around it is to explicitly add an else clause that simply returns D:
UPDATE my_table
SET D = CASE
WHEN (A = 6 AND B = 1 AND C = 'red') THEN '1#2#3#5#4'
WHEN (A = 8 AND B = 1 AND C = 'green') THEN '5#6#7#8#9'
ELSE D
END
Another way, which is a bit "clunkier" in syntax, but may perform slightly better, is to add a where clause so only the relevant rows are updated:
UPDATE my_table
SET D = CASE
WHEN (A = 6 AND B = 1 AND C = 'red') THEN '1#2#3#5#4'
WHEN (A = 8 AND B = 1 AND C = 'green') THEN '5#6#7#8#9'
END
WHERE (A = 6 AND B = 1 AND C = 'red') OR (A = 8 AND B = 1 AND C = 'green')

Related

SQL view to get records that don't match the JOIN condition

I have been trying to get my head around this but not yet found a solution. I am dealing with a SQL view whose results are based on certain conditions. My SQL View is as below
ALTER VIEW [dbo].[vAeoiCaseClose]
AS
SELECT CaseReference, s.AccessNumber
FROM dbo.AeoiSdtTemp s
JOIN AeoiCaseManagement c on c.AccessNumber = s.AccessNumber
JOIN AeoiCaptureLog a on a.AccessNumber = c.AccessNumber
WHERE AscertainMethodId IS NOT NULL
AND c.StatusCode = 15 AND a.StatusCode IN (6, 13, 15)
AND DATEDIFF(dd, s.LastModifiedDate, GETDATE()) <= 80 AND DATEDIFF(dd, a.LastModifiedDate, GETDATE()) <= 80
AND (
(AscertainMethodId = 1 AND ExtendedStatusId = 1)
OR (AscertainMethodId = 2 AND ExtendedStatusId = 1)
OR (AscertainMethodId = 2 AND ExtendedStatusId = 4)
OR (AscertainMethodId = 3 AND ExtendedStatusId = 1)
OR (AscertainMethodId = 3 AND ExtendedStatusId = 4)
OR (AscertainMethodId = 4 AND ExtendedStatusId = 1)
OR (AscertainMethodId = 5 AND ExtendedStatusId = 1)
OR (AscertainMethodId = 5 AND ExtendedStatusId = 4)
)
GO
I have to add another condition, so those records are also avaialble as result of the view.
Condition:
In some cases there might be 2 records in dbo.AeoiSdtTemp with same (AccessNumber) but different (AscertainMethodId) , in this case the record won't be available in AeoiCaptureLog table, But i need those as part of the result of the view.
Please suggest. Appreciate help.
Example:
dbo.AeoiSdtTemp
(AccessNumber) - 1111 (AscertainMethodId) - 3 StatusCode = 15
(AccessNumber) - 1111 (AscertainMethodId) - 5 StatusCode = 11
dbo.AeoiCaptureLog
NO RECORD
dbo.AeoiCaseManagement
(AccessNumber) - 1111 (AscertainMethodId) - 3 StatusCode = 15
A quick and dirty starting point without testing: Use a second alias (s1 and s2 instead of s, or s and s1) to join the dbo.AeoiSdtTemp table to itself using the s.AccessNumber, like so:
...
FROM dbo.AeoiSdtTemp s1
...
JOIN dbo.AeoiSdtTemp s2 ON (
s2.AccessNumber = s1.AccessNumber
AND s2. AscertainMethodId != s1. AscertainMethodId
)
...
Also, do a review of LEFT vs RIGHT and INNER vs OUTER joins, which will help you determine the way that the clause above will affect your resulting data.

If the column is empty, select the same column using different where clause

Is there a way to select rpd.name using a different WHERE clause if the previous one returns an empty string?
I've looked into CASE, but I'm not sure how would I go about using it.
table replacement_part
part_id href
1 url_1
2 url_2
3 url_3
table replacement_part_description
part_id language_id name
1 2
1 1 hose
2 2
2 1 control module
3 2 vonkajsi kryt
3 1 outer casing
expected output
part_id href name
1 url_1 hose
2 url_2 control module
3 url_3 vonkajsi kryt
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE language_id = :id
So something like
if rpd.name = ''
WHERE language_id = a,
else
WHERE language_id = b
This ?
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE
(
language_id = :id
AND (rpd.name = '' OR rpd.name IS NULL)
)
OR language_id = b
One way is to join the rpd table twice, moving the where clause on the ON condition, and then use COALESCE:
SELECT
...,
COALESCE(rpd1.name, rpd2.name) AS name
FROM
replacement_part rp LEFT JOIN replacement_part_description rpd1
ON rp.part_id = rpd1.part_id AND rpd1.language=a
LEFT JOIN replacement_part_description rpd2
ON rp.part_id = prd2.part_id AND rpd2.language=b
here I suppose that the language is on the description table. If name is an empty string, instead of coalesce you could use CASE WHEN:
CASE WHEN rpd1.name='' OR rpd1.name IS NULL THEN rpd2.name ELSE rpd1.name END AS Name
You can use order by and limit to get one row with priorities:
select . . .
from . . .
where (language_id = a and rpd.name = '') or
language_id = b
order by (language_id = a) desc -- put the "a" rows first
limit 1;

SQL query to set a value if data exist

Here's the fiddle;
http://sqlfiddle.com/#!2/af8015/9
I've some data, and I want to set
if user and g parameter are in table named cl, result column should
be 1;
if user and g parameter are in table named im, but not in cl, result
column should be -1;
else, result column should be 0
I'm using following query;
select *,
case cl.user_id
when null then -1
when im.user_id then 1
end as result
from im
left join cl on cl.user_id = im.user_id
and cl.id_g = im.id_g
left join user on user.user_id = im.user_id
left join g on g.id_g = im.id_g
But, it returns null for -1, and I couldn't set 0 for the last case.
Expected result table is;
user id - g id - result
1 1 1
1 2 1
1 3 0
1 4 1
2 1 1
2 2 1
2 3 -1
2 4 0
...
I can't see a way of generating the 0 result from your sample data.
I believe your result parameter should be computed like this;
IF (cl.user_id IS NOT NULL and cl.id_g IS NOT NULL, 1,
IF(im.user_id IS NOT NULL and im.id_g IS NOT NULL, -1,0)
) result
And, I think your series of JOIN operations should go like this.
FROM user
LEFT JOIN im ON user.user_id = im.user_id
LEFT JOIN cl ON user.user_id = cl.user_id AND im.id_g = cl.id_g
LEFT JOIN g ON im.id_g = g.id_g
That is, you should lead with the user table. Here's an example: http://sqlfiddle.com/#!2/a5c6ef/1/0
Your result parameter is computed like this:
case cl.user_id
when null then -1
when im.user_id then 1
end as result
null values work strangely. A null value can never compare equal to anything, even another null value, so when null then -1 will never fire. This expression, on the other hand, should work.
case when cl.user_id IS NULL then -1
when im.user_id IS NULL then 1
else 0 end as result

tsql multipe update on single table

Is there a way to update a table based on multiple where clause. In one single statement?
update A
set Final = '21'
from StudentTable A
where Student_ID= 4 and bitcm= 0 and receipt= 17
update B
set Final = '22'
from StudentTable B
where Student_ID=4 and bitcm= 0 and receipt =12
update C
set Final ='11'
from StudentTable C
where Student_ID=4 and bitcmp=1 and receipt=17
update D
set Final ='12'
from StudentTable D
where Student_ID=4 and bitcmp=1 and receipt=12
Is there a way to combine all this statement into a single statement?
Yes, there is:
UPDATE A
SET Final = CASE WHEN bitchcm = 0 AND receipt = 17 THEN '21'
WHEN bitchcm = 0 AND receipt = 12 THEN '22'
WHEN bitchcm = 1 AND receipt = 17 THEN '11'
WHEN bitchcm = 1 AND receipt = 12 THEN '12'
END
FROM StudentTable A
WHERE Student_ID = 4 AND -- the purpose of the three conditions
bitcm IN (0,1) AND -- is to speed up the query. It will not
receipt IN (12,17) -- scan the whole records on the table
If column FINAL is INT then you don't need to wrap the values with single quotes.
If those are the only four rows for Student_ID 4, then the following works:
update A
set Final = CASE
WHEN bitcm=0 and receipt=17 THEN '21'
WHEN bitcm= 0 and receipt =12 THEN '22'
WHEN bitcmp=1 and receipt=17 THEN '11'
WHEN bitcmp=1 and receipt=12 THEN '12'
END
from StudentTable A
where Student_ID= 4
(I assume bitcm and bitcmp are meant to be the same column, but I'm not sure which spelling to use)
A more general approach would be to have a table (table variable or parameter, probably) containing all required key columns and the new Final value. You'd then write:
UPDATE A
SET Final = B.Final
FROM StudentTable A
INNER JOIN #AboveMentionedTableVariableOrParameter B
ON
A.Student_ID = B.Student_ID and
A.bitcm = b.bitcm and
A.receipt = b.receipt --And add any other necessary conditions here.
You could use a CASE Statement
UPDATE StudentTable
SET Final =
CASE WHEN Student_ID= 4 and bitcm= 0 and receipt= 17 THEN 21
WHEN Student_ID=4 and bitcm= 0 and receipt =12 THEN 22
WHEN Student_ID=4 and bitcmp=1 and receipt=17 THEN 11
WHEN Student_ID=4 and bitcmp=1 and receipt=12 THEN 12
END
WHERE Student_ID = 4
AND bitcm IN (0,1)
AND receipt IN (12,17)

MySQL stored procedure: IF in WHERE

I am trying to select some data in the following manner:
SELECT column
FROM table
WHERE a = a1
AND (b = b1 OR b = b2 OR b = b3);
What I want it to do is if b is not equal to b1, check if b=b2. However, if b=b1, do not check other conditions.
The result of this select statement must be only one entry. However, in the statement I have no, it checks all of the three conditions and sometimes returns multiple rows. Again, I would like it to stop checking if the condition is true.
Any ideas on how could this be implemented? I tried case but it did not work out...
Thank you in advance!
EDIT
Here is an actual query i am trying to run.
INSERT INTO shipment_flights
(airlinename, flt_no, flt_date, destination, phone, depttime, arrivaltime, pcs, weight)
SELECT st.airlinename, flightno, flightdate, destination,
(SELECT phone
FROM carrierlocations
WHERE carriers_carrierid = (select carrierid from carriers where airlinename = st.airlinename)
AND (city = destination OR (city != destination AND
city = (SELECT city FROM airports WHERE iataid =
(SELECT airports_iataid FROM ratelegs
WHERE shipments_shipid = c.shipments_shipid))
))) phone,
depttime, arrivaltime, sum(linepcs), sum(lineweight)
FROM segment_times st
JOIN contents2flights c2f
ON st.flightid = c2f.segments_flights_flightid
AND st.segmentid = c2f.segments_segmentid
JOIN contents c
ON c.lineno = c2f.contents_lineno
AND c.shipments_shipid = c2f.contents_shipments_shipid
WHERE c.shipments_shipid = var_shipid
GROUP BY flightid
ORDER BY flightdate, depttime;
Here is a sample output:
airlinename flt_no flt_date destination phone pcs weight
Everts Air Alaska CH1 2008-02-20 Hughes 9074502351 24 2121
The query inserts bunch of flight data into temporary table. What I am having trouble with is getting a phone number for a location. This part is as follows:
(SELECT phone
FROM carrierlocations
WHERE carriers_carrierid = (select carrierid from carriers where airlinename = st.airlinename)
AND (city = destination OR (city != destination AND
city = (SELECT city FROM airports WHERE iataid =
(SELECT airports_iataid FROM ratelegs
WHERE shipments_shipid = c.shipments_shipid))))) phone
In the query advised by Amit Bhargava, I get the right result only if there is one row in the temporary table. If there are more, it throws an error in the selecting phone part.
"Error Code: 1242. Subquery returns more than 1 row"
By using IF() + IF() + IF(), and testing the sum = 1 prevents a lot of extra and not of the other criteria. If 2 or all 3 are the same, the summation will be greater than 1. If none of them match, the result is 0. This should get exactly what you want.
SELECT column
FROM table
WHERE a = a1
AND if( b = b1, 1, 0 )
+ if( b = b2, 1, 0 )
+ if( b = b3, 1, 0 ) = 1
Or... as assisted by ypercube, and I keep forgetting logical tests return either 1 or 0 for true / false respectively, such as...
SELECT column
FROM table
WHERE a = a1
AND (b = b1) + (b = b2) + (b = b3) = 1
Please try the following. Not the most elegant solution, but it should work.
SELECT column
FROM table
WHERE a = a1
AND (b = b1 OR (b != b1 AND (b = b2 OR (b != b2 AND b = b3))))