tsql multipe update on single table - sql-server-2008

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)

Related

MySQL Select User id based on multiple AND conditions on same table

I want to select a userid from a single table based on multiple and condition.
UserID FieldID Value
-----------------------------------
1 51 Yes
1 6 Dog
2 6 Cat
1 68 TX
1 69 78701
2 68 LA
What I'm trying to get in simple words:
if user search for texas or 78701,
Select userId where (68 = TX OR 69=78701) AND (51=yes) AND (6=Dog)
This should return user id 1.
This is what I tried, but returns null.
SELECT user_id FROM `metadata`
WHERE ( (`field_id` = '68' AND value LIKE '%TX%')
OR (`field_id` = '69' AND value LIKE '%78701%') )
AND `field_id` = '51' AND value = 'Yes'
AND `field_id` = '6' AND value = 'Dog'
You can use GROUP BY with a HAVING clause that makes use of multiple conditional aggregates:
SELECT UserID
FROM metadata
GROUP BY UserID
HAVING SUM(field_id = '68' AND value LIKE '%TX%' OR
field_id = '69' AND value LIKE '%78701%') >= 1
AND
SUM(field_id = '51' AND value = 'Yes') >= 1
AND
SUM(field_id = '6' AND value = 'Dog') >= 1
Demo here
Explanation: In MysQL a boolean expression, like
field_id = '51' AND value = 'Yes'
returns 1 when true, 0 when false.
Also, each predicate of HAVING clause is applied to the whole group of records, as defined by GROUP BY.
Hence, predicate:
SUM(field_id = '51' AND value = 'Yes') >= 1
is like saying: return only those UserID groups having at least one (>=1) record with
field_id = '51' AND value = 'Yes' -> true
Your table structure resembles attribute+value modelling, which essentially splits up the columns of a row into individual pairs, and has the side effect of very weak typing.
As you've noted, this can also make things tricky to query, since you have to reason over multiple rows in order to make sense of the original data model.
One approach could be to take an opinion of a 'primary' criterion, and then apply additional criteria by reasoning over the shredded data, joined back by user id:
SELECT DISTINCT m.user_id
FROM `metadata` m
WHERE ((`field_id` = '68' AND value LIKE '%TX%')
OR (`field_id` = '69' AND value LIKE '%78701%'))
AND EXISTS
(SELECT 1
FROM `metadata` m2
WHERE m2.user_id = m.user_id AND m2.field_id = '51' AND m2.value = 'Yes')
AND EXISTS
(SELECT 1
FROM `metadata` m3
WHERE m3.user_id = m.user_id AND m3.field_id = '6' AND m3.value = 'Dog');
However, IMO, it may be better to attempt to remodel the table like so (and ideally choose better descriptions for the attributes as columns):
UserID Field51 Field6 Field68 Field69
----------------------------------------
1 Yes Dog TX 78701
2 No Cat LA NULL
This will make things much easier to query.
This approach is typically slower than simply LEFT JOINing that table on each criterion, but it can make the problem simpler to comprehend...
SELECT userid
, MAX(CASE WHEN fieldid = 51 THEN value END) smoker
, MAX(CASE WHEN fieldid = 6 THEN value END) favourite_pet
, MAX(CASE WHEN fieldid = 68 THEN value END) state
, MAX(CASE WHEN fieldid = 69 THEN value END) zip
FROM eav
GROUP
BY userid;
You can use HAVING, or bundle this into a subquery to get the desired results.
SELECT user_id FROM metadata
WHERE
(field_id = '68' AND value LIKE '%TX%')
OR (field_id = '69' AND value LIKE '%78701%')
AND (field_id = '51' AND value = 'Yes')
AND (field_id = '6' AND value = 'Dog');
I have little bit changed your query and tried with the same,it gives output as, user_id is 1

Conditional condition in ON clause

I am trying to apply a conditional condition inside ON clause of a LEFT JOIN. What I am trying to achieve is somewhat like this:
Pseudo Code
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND (some condition)
AND (
IF (s.type = 0 AND s.code = 'me')
ELSEIF (s.type = 1 AND s.code = 'my-group')
ELSEIF (s.type = 2)
)
I want the query to return the row, if it matches any one of the conditions (Edit: and if it matches one, should omit the rest for the same item).
Sample Data
Sales
item_no | type | code | price
1 0 me 10
1 1 my-group 12
1 2 14
2 1 my-group 20
2 2 22
3 2 30
4 0 not-me 40
I want the query to return
item_no | type | code | price
1 0 me 10
2 1 my-group 20
3 2 30
Edit: The sales is table is used to apply special prices for individual users, user groups, and/or all users.
if type = 0, code contains username. (for a single user)
if type = 1, code contains user-group. (for users in a group)
if type = 2, code contains empty-string (for all users).
Use the following SQL (assumed, the the table sales has a unique id field as usual in yii):
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND id = (
SELECT id FROM sales
WHERE item_no = i.sku
AND (type = 0 AND code = 'me' OR
type = 1 AND code = 'my-group' OR
type = 2)
ORDER BY type
LIMIT 1
)
Try following -
SELECT *,SUBSTRING_INDEX(GROUP_CONCAT(s.type ORDER BY s.type),','1) AS `type`, SUBSTRING_INDEX(GROUP_CONCAT(s.code ORDER BY s.type),','1) AS `code`,SUBSTRING_INDEX(GROUP_CONCAT(s.price ORDER BY s.type),','1) AS `price`
FROM item AS i
LEFT JOIN sales AS s
ON i.sku = s.item_no AND (SOME CONDITION)
GROUP BY i.sku

Update Case When, with multiple conditions

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')

MySQL UPDATE not updating properly

I've got an UPDATE query as followed:
UPDATE orders
SET
order_status = 1,
amount_remaining = 0.00000000
WHERE
market_pair_id = 2 AND user_id = 1
AND sale_rate = 0.00000001
AND sale_amount = 100.00000000
AND order_type = 1 LIMIT 1
Here's a snapshot of my data from phpmyadmin:
http://cl.ly/image/3m3M2f2R3R3Z/Screen%20Shot%202014-01-20%20at%2012.55.03.png
There's clearly 3 matching rows for my query however none of them are updated with the message 0 rows affected. Can someone shed light on what's going on?
Some added info: I can't update via the primary key because I dont have it, and my goal is simply to update 1 of many matching rows of my data.
Thanks very much in advance
Delete LIMIT 1 from end of your query and try
UPDATE orders
SET
order_status = 1,
amount_remaining = 0.00000000
WHERE
market_pair_id = 2 AND user_id = 1
AND sale_rate = 0.00000001
AND sale_amount = 100.00000000
AND order_type = 1
.try this
UPDATE orders
SET
order_status = 1,
amount_remaining = 0.00000000
WHERE order_id IN (
SELECT order_id FROM (
SELECT order_id FROM orders
WHERE market_pair_id = 2
AND user_id = 1
AND sale_rate = 0.00000001
AND sale_amount = 100.00000000
AND order_type = 1
LIMIT 1
) tmp
);

mysql conditional field update

I have 3 columns in CATEGORY TABLE for storing pre-calculated counts of records for it in another table PRODUCTS.
CATEGORY(c_id,name,c30,c31,c32)
c30=count for New Products (value 30)
c31 count for used products (value 31)
c32 count for Damaged products (value 32)
PRODUCT(p_id,c_id,name,condition)
condition can be 30,31 or 32.
I am thinking to write a single UPDATE statement so, it will update respective category count.
Althogh below statement is syntactically wrong, but i am looking for similar type of solution.
select case product.condition
when 30 then update category set category.c30=category.c30+1 where category.c_id=product.category3
when 31 then update category set category.c31=category.c31+1 where category.c_id=product.category3
when 32 then update category set category.c32=category.c32+1 where category.c_id=product.category3
end case
from product
where product.c_id=12
Any suggestion!
You can do this:
UPDATE CATEGORY c
INNER JOIN
(
SELECT
c_id,
SUM(CASE WHEN `condition` = 30 THEN 1 ELSE 0 END) c30,
SUM(CASE WHEN `condition` = 31 THEN 1 ELSE 0 END) c31,
SUM(CASE WHEN `condition` = 32 THEN 1 ELSE 0 END) c32
FROM product
GROUP BY c_id
) p ON c.c_id = p.c_id
SET c.c30 = p.c30,
c.c31 = p.c31,
c.c32 = p.c32;
SQL Fiddle Demo
You can join both the tables and then update the value in same join query.