MySQL UPDATE not updating properly - mysql

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

Related

SQL INSERT or UPDATE in statements

I'm new to SQL and I want to create an INSERT or Update query for my webpage. I have two buttons, Status and Shipped, next to every item. If the user presses one of these buttons, it calls a php file with a query. But I really dont know how to put together these 2 queries into 1.
Items
STATUS
SHIPPED
Item1
STATUS
SHIPPED
Item2
STATUS
SHIPPED
Item3
STATUS
SHIPPED
Status Button
IF status NOT EXIST WHERE user_id = 17 AND item_id = 5
THEN INSERT INTO table1 VALUE (status = 1) WHERE user_id = 17 AND item_id = 5
BUT, IF shipped = 1 AND status = 0 WHERE user_id = 17 AND item_id = 5
THEN UPDATE table1 SET status = 1
Shipped Button
IF shipped NOT EXIST WHERE user_id = 17 AND item_id = 5
THEN INSERT INTO table1 VALUE (shipped = 1) WHERE user_id = 17 AND item_id = 5
BUT, IF staus = 1 AND shipped = 0 WHERE user_id = 17 AND item_id = 5
THEN UPDATE table1 SET shipped = 1
Query to filter out non essecial rows
IF status = 0 AND shipped = 0 WHERE user_id = 17 AND item_id = 5
THEN DELETE row WHERE user_id = 17 AND item_id = 5
Thank you!

Create a status column with results based on another table using a case statement

I have 2 tables
orders
order_id
1
2
3
orders_details
order_id
sku
ordered
received
1
abc
10
10
1
xyz
10
10
2
abc
10
6
2
xyz
10
0
3
abc
10
0
4
xyz
10
0
I would like to add to the orders table a column called status which would have the results 'complete', 'partial' and 'open' based on what has been received in the orders_details table
result I am trying to acheive
order_id
status
1
complete
2
partial
3
open
The problem is when a different product from the same order_id has a different received result it creates an additional row with the group by.
result I am getting
order_id
status
1
complete
2
open
2
partial
3
open
https://www.db-fiddle.com/f/bFrYguhmcMJ32iFuUcXfDw/3
SELECT
`orders`.`order_id`,
(CASE
WHEN `received` >= `ordered` THEN 'complete'
WHEN `received` < `ordered` AND `received` != 0 THEN 'partial'
WHEN `received` = 0 THEN 'open'
END) AS `status`
FROM
`orders`
LEFT JOIN `orders_details` ON `orders_details`.`order_id` = `orders`.`order_id`
GROUP BY
`order_id`, `status`
;
I might be missing something, but I think you just want:
SELECT `orders`.`order_id`,
CASE SUM(received)
WHEN 0 THEN 'open'
WHEN SUM(ordered) THEN 'complete'
ELSE 'partial'
END AS `status`
FROM `orders`
LEFT JOIN `orders_details`
ON `orders_details`.`order_id` = `orders`.`order_id`
GROUP BY `order_id`;
Here's your updated DB Fiddle
It is a bit hacky, but you can define the order by giving then names of the status an order the should be choosen, and then take the maximum for this order.
Zcomplete>partial>open
We can thenremove the additional charatcers
Query #1
SELECT
`orders`.`order_id`,
REPLACE (MAX((CASE
WHEN `received` >= `ordered` THEN 'Zcomplete'
WHEN `received` < `ordered` AND `received` != 0 THEN 'partial'
WHEN `received` = 0 THEN 'open'
END)), 'Z', '') AS `status`
FROM
`orders`
LEFT JOIN `orders_details` ON `orders_details`.`order_id` = `orders`.`order_id`
GROUP BY
`order_id`
;
order_id
status
1
complete
2
partial
3
open
View on DB Fiddle

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

SQL table update all but the most recent record for every Id

Considering the below table where is have 4 difference customers with more than 1 orders each.
I need to updated the column XYZ to 1 for each customer depending on the date created column.
Update the table1 set xyz = 1
condition only the latest ( date created ) order should have XYZ value as 0
Customerid Orderid Date Created XYZ
12193438 13393354 09/08/2011 16:35 0
12193438 13384318 05/08/2011 14:08 0
12193438 13384458 08/08/2011 14:01 0
21801966 13379456 06/08/2011 12:59 0
21801966 13380639 06/08/2011 16:42 0
21971567 13385322 22/08/2011 18:00 0
21971567 13380200 09/08/2011 21:03 0
66697824 13389263 07/08/2011 13:44 0
66697824 13380162 08/08/2011 15:48 0
IT should look as below
Customerid Orderid Date Created XYZ
12193438 13393354 09/08/2011 16:35 0
12193438 13384318 05/08/2011 14:08 1
12193438 13384458 08/08/2011 14:01 1
21801966 13379456 06/08/2011 12:59 1
21801966 13380639 06/08/2011 16:42 0
21971567 13385322 22/08/2011 18:00 0
21971567 13380200 09/08/2011 21:03 1
66697824 13389263 07/08/2011 13:44 1
66697824 13380162 08/08/2011 15:48 0
UPDATE thetable tt
SET xyz = 1
WHERE EXISTS (
SELECT * FROM thetable ex
WHERE ex.customerId = tt.customerId
AND ex.dateCreated > tt.dateCreated
);
You can do this by using update and join. This version uses aggregation to find the right rows to update:
update xyz join
(select customerid, max(datecreated) as maxdc
from xyz
group by customerid
) cd
on xyz.customerid = cd.customerid and xyz.datecreated < cd.maxdc
set xyz.XYZ = 1;
To maintain the data over time, you might consider consider using triggers.
If you want to set both 0 and 1 at the same time (so not assume that everything starts as 0, you an do:
update xyz join
(select customerid, max(datecreated) as maxdc
from xyz
group by customerid
) cd
on xyz.customerid = cd.customerid
set xyz.XYZ = xyz.datecreated < cd.maxdc;
so for each customer ,latest ( date created ) order should have XYZ value as 0 and other has 1
Update the table1
set xyz = 1 where OrderID not in (select OrderID from (select * from table1 order by DateCreated desc)a group by CustomerID,OrderID)b
Assumption - XYZ default value is 0
Update the table1 set xyz = 1 where datecreated < '<your date you want>'
this will set 1 to all xyz for which datecreated is less than what you specify. PS: datecreated should be an index for it to work fast.
This involves shifitng the data into table2 and then updating table2 to populate the XYZ column.
select *,RANK()over(partition by customerid order by date_created desc) as dateorder into table2
from table1
update table2 set XYZ = 1 where dateorder not like 1
It might seem strange that table1 itself is not updated...the RANK function is an analysis processing tool which doesn't necesarily work without the creation of an analysis table. This is mainly based in the fact that table1 is busy receiving the order data! Here, table1 (transaction table) can carry on recieving data (transacting) and, at less busy times, data added since the last analysis can be shifted out of it and onto table2 (analysis table):
DECLARE #customerid INT -- used for file name
DECLARE db_cursor CURSOR FOR
SELECT distinct customerid
FROM orders
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #customerid
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE Orders
set XYZ = 1
where Orderid <> (select top 1 Orderid from orders where Customerid = #customerid order by DateCreated desc)
and Customerid = #customerid
FETCH NEXT FROM db_cursor INTO #customerid
END
CLOSE db_cursor
DEALLOCATE db_cursor

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)