Update MySQL record twice using 'CASE' - mysql

I am working on an accountant software , some times the invoice contain the same item id twice (every one with its unique serial number) .. so after selling the two items I need its quantity equals quantity-1
I am using this statement for updating some records
UPDATE `table1` SET `quantity` = CASE
WHEN id = 1 THEN quantity-1
WHEN id = 1 THEN quantity-1
END
WHERE id in (1)
after updating using this statement ,the value of quantity ignores the second statement
How can I solve this ?
EDIT
The answer
Thank You ... I found the trick by myself
UPDATE `table1` SET `quantity` = CASE
WHEN id = (1*(1/1)) THEN quantity-1
WHEN id = (1*(2/2)) THEN quantity-1
WHEN id = (1*(3/3)) THEN quantity-1
END
WHERE id in (1)
the record will be updated 3 times by the same query
why I need This ?
because my software accepts that the user can add the same (Product ID) many times in the same invoice so I need the query to update the quantity many times in the same statement for one (Product ID)

I think this might actually be what you want. I have id=1 in my table 3 times, so mcount is set equal to 3. The row for ID=2 was not updated because of the where condition.
update table1
join (select id, count(*) as ct from table1 group by id) as ct_tbl
set mcount = ct_tbl.ct
where table1.id=1
mysql> select * from table1;
+------+--------+
| id | mcount |
+------+--------+
| 1 | 3 |
| 1 | 3 |
| 1 | 3 |
| 2 | 0 |
+------+--------+
4 rows in set (0.00 sec)
I don't want to hijack the other answer because it's totally correct but I think it needs more explanation.
UPDATE `table1` SET `mcount` = CASE
WHEN id = 1 THEN 1
WHEN id = 1 THEN 2
END
WHERE id in (1)
that is the equivalent of... (psuedo)
in the table table1
where the id = 1
if id = 1 then set mcount = 1
if id = 1 then set mcount = 2
Because of the where statement, we already know that we will only select rows where id=1. Those if statements will just overwrite each other. I really don't know what you're after but normally...
the following will add one to mcount
UPDATE `table1`
SET `mcount` = mcount + 1;
WHERE id in (1)
the following will toggle mcount values
UPDATE `table1`
SET `mcount` = CASE WHEN mcount = 1 THEN 2
WHEN mcount = 2 THEN 1 END
WHERE id in (1)
the following will toggle mcount values
UPDATE `table1`
SET `mcount` = CASE WHEN other_field = 'Y' THEN 1
WHEN other_field = 'N' THEN 2 END
WHERE id in (1)
working with multiple ID values...
UPDATE `table1`
SET `mcount` = CASE WHEN id = 1 THEN 1
WHEN id = 2 THEN 2
WHEN id = 3 THEN 3 END
WHERE id in (1,2,3)
which is the same as...
UPDATE `table1`
SET `mcount` = id
WHERE id in (1,2,3)
now the real question is... if ID=1 then what should mcount be?
also....
set #row:=0;
update table1
set mcount = #row:=#row+1
where id = 1;
mysql> select * from table1;
+------+--------+
| id | mcount |
+------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 0 |
+------+--------+
4 rows in set (0.00 sec)

Your statement has the same condition for each case, always will return 1 (first statement), the second statement will be ignored because it is the same condition.

Thank You ... I found the trick by myself
UPDATE `table1` SET `quantity` = CASE
WHEN id = (1*(1/1)) THEN quantity-1
WHEN id = (1*(2/2)) THEN quantity-1
WHEN id = (1*(3/3)) THEN quantity-1
END
WHERE id in (1)
the record will be updated 3 times by the same query

Related

Select rows where column > 0 after final row where column == 0

Edit 2021: I want to explain this better.
I have a table named MyTable with two columns; one column named SortColumn type Integer and one column named ExpressionColumn type Boolean.
I want to get all rows, sorted by SortColumn in ascending order, after the last row where ExpressionColumn was True.
The types are not exact.
Eg. Table with rows represented as [SortColumn,ExpressionColumn], [0:True] will get [0:True], [0:True, 1:False] will get [], [0:True, 1:False, 2:True, 3:True] will get [3:True, 4:True].
Leaving the old question below so as not to invalidate given answers. It had too many extra details.
I want to select rows after than last row where column Number is 0.
So with this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
I want to get rows with Id 0 to 3 inclusive.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
I want to get no rows at all.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
5 | 0
6 | 30
I want to get row with Id 6.
SQL details: MySQL 5.6.
Retrieve separate records:
SELECT *
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%' -- maybe not needed? not specified
AND Price = 0 );
Retrieve their amount only:
SELECT COUNT(*)
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%'
AND Price = 0 );
fiddle
you can select
select
from my_table
where name like '%car%' and price > 0
and for count
select count(*)
from (
select
from my_table
where name like '%car%' and price > 0
) t
I interpret this question as "how many rows are there for "car wash" after the first row with price > 0". If so:
select count(*)
from (select t.*,
min(case when price = 0 then id end) over () as id_at_0
from transaction t
) t
where name = 'Car Wash' and id > id_at_0
SELECT * FROM MyTable myTable1
AND NOT EXISTS ( SELECT NULL FROM MyTable
WHERE myTable1.SortColumn <= SortColumn
AND ExpressionColumn = True );

Manage hours and data in sql query

I'm planning to study a small webapp in php. I am faced with a problem concerning an SQL query to be performed.
Basically I have to manage reservations based on the date and time. I have separated the two things in a form with a type = date and a type = time.
The date is "data".
The hour is "orario_inizio".
this is my form:
Data: <br><input type="date" name="data" ><br>
Orario Inizio: <br><input type="time" name="orario_inizio" min="09:30:00" max="16:30:00"><br>
Orario Fine: <br><input type="time" name="orario_fine" min="10:00:00" max="18:30:00"><br>
In order for a reservation to be entered in the database it is necessary that "orario_inizio" we have a space of two hours, that is that in the following two hours there are no other bookings.
input.php
// Richiedente
$nominativo = $_POST['nominativo'];
$email = $_POST['email'];
$oggetto = $_POST['oggetto'];
$data = $_POST['data'];
$orario_inizio = $_POST['orario_inizio'];
$orario_fine = $_POST['orario_fine'];
//inserting data order
$query1 = "INSERT INTO Prenotazione (nominativo,email,data,orario_inizio,orario_fine,oggetto,nominativoi,emaili,nominativoe,emaile) VALUES ('$nominativo','$email','$data','$orario_inizio','$orario_fine','$oggetto','$nominativoi','$emaili','$nominativoe','$emaile')"; $result1 = mysqli_query($conn, $query1 );
$result1 = mysqli_query($conn, $query1 );
?>
What I can not understand is how to develop a query that allows me to consider for the date chosen by the user that there are no bookings within two hours. Let me explain with an example:
The user1 wants to make a reservation per day 24 / sept at 10:30 am. I have to make sure that there are no reservations until 12:30. If there are no other bookings already made then I would like to enter this reservation if I send an alert.
I have done the second part, the insert into the database, but i don't have idea how to do about the first check.
$query1 = "INSERT INTO Prenotazione (nominativo,email,data,orario_inizio,orario_fine,oggetto,nominativoi,emaili,nominativoe,emaile) VALUES ('$nominativo','$email','$data','$orario_inizio','$orario_fine','$oggetto','$nominativoi','$emaili','$nominativoe','$emaile')";
I have read that a possibility should be the use of SUBDATE
Can you help me? thank you
UPDATE.
Table Prenotazione
database
Since you provided no table schema, I'll have to use placeholder column names etc.
As explained through comments earlier, you can use the mysql function BETWEEN to see if something is "between" the given times (works for dates also). What it does, is it returns a boolean value. 1 if true, 0 if false.
assuming your table has a date row in order to see the bookings for specific dates, you could write the following example:
$sql="SELECT
COUNT(column_id)
FROM
table_name
WHERE
TIME($orario_inizio) BETWEEN '10:30' AND '12:30'
AND date_column=CURDATE()";
$result_set=mysqli_query($conn, $sql);
$checkIfValid=mysqli_fetch_array($conn, $result_set)[0];
if($checkIfValid > 0) {
//throw error
}
else {
//perform insert query
}
You can tweak the logic to fit your liking a bit better. For instance, CURDATE() just takes the current date, but perhaps you have a specific booking date you can use?
This SQL basically counts an id of your choice (user id or whatnot) based on the condition that the time is between 10:30 AM and 12:30 AM, and that the date is today (could be a given booking date instead).
Now, if this sql finds any records, it will be put into the count. So it either has a value of 0 or higher. If the count is higher than 0, then that means we are busy or however the logic is applied, meaning that you cannot make a booking for that day / time period, and so we throw an error. However, if the count is not bigger than 0, then we proceed with our INSERT, because then everything must be okay.
Consider the following:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table(booking_id SERIAL PRIMARY KEY,booking_start INT NOT NULL);
INSERT INTO my_table (booking_start) VALUES (3),(7),(10);
SET #n = 9;
INSERT INTO my_table (booking_start)
SELECT #n
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.booking_start BETWEEN #n AND #n+2
WHERE y.booking_start IS NULL
LIMIT 1;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM my_table;
+------------+---------------+
| booking_id | booking_start |
+------------+---------------+
| 1 | 3 |
| 2 | 7 |
| 3 | 10 |
+------------+---------------+
3 rows in set (0.00 sec)
-- Nothing happens, because 10 is between 9 and 11.
SET #n = 8;
INSERT INTO my_table (booking_start)
SELECT #n
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.booking_start BETWEEN #n AND #n+2
WHERE y.booking_start IS NULL
LIMIT 1;
SELECT * FROM my_table;
+------------+---------------+
| booking_id | booking_start |
+------------+---------------+
| 1 | 3 |
| 2 | 7 |
| 3 | 10 |
+------------+---------------+
3 rows in set (0.00 sec)
-- Nothing happens, because 10 is between 8 and 10.
SET #n = 7;
INSERT INTO my_table (booking_start)
SELECT #n
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.booking_start BETWEEN #n AND #n+2
WHERE y.booking_start IS NULL
LIMIT 1;
SELECT * FROM my_table;
+------------+---------------+
| booking_id | booking_start |
+------------+---------------+
| 1 | 3 |
| 2 | 7 |
| 3 | 10 |
+------------+---------------+
3 rows in set (0.00 sec)
-- Nothing happens, because 7 is between 7 and 9.
SET #n = 4;
INSERT INTO my_table (booking_start)
SELECT #n
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.booking_start BETWEEN #n AND #n+2
WHERE y.booking_start IS NULL
LIMIT 1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM my_table;
+------------+---------------+
| booking_id | booking_start |
+------------+---------------+
| 1 | 3 |
| 2 | 7 |
| 3 | 10 |
| 4 | 4 |
+------------+---------------+
4 rows in set (0.00 sec)
-- Success, because there is no value between 4 and 6.

mysql - update distinct row in one table

I have this table:
it produces by this query SELECT DISTINCT code, tariff_diff FROM mytable
.
Now, I want to update tariff_diff = 1 if code appear more than 1. (as example, I want to update tariff_diff = 1 where row Kuta,DPS50xxx)
I have tried :
update mytable SET tariff_diff = 1
WHERE in(select distinct code, tariff_diff from mytable)
But i am getting error syntax.
Operand should contain 1 column
If you want to alter the all the rows with same code you can use this.
UPDATE mytable SET mytable.tariff_diff = 1 WHERE mytable.code IN(SELECT count(*), code, tariff_diff from mytable GROUP BY code HAVING count(*)>1)
It is not possible to use same update table in select statement in subquery , you can find the reason in this link: Reason for not use same table in sub-query.
try below query:
SET #r_code = (select code from mytable GROUP BY code having count(code) > 1);
update mytable SET tariff_diff = 1 WHERE code in (#r_code);
You can find more about variable here in this link.More about Variables.
First of all store the id's into the some variable and then update those id's using in query.
From what I understand, you're wanting to set the tariff_diff to 1 only if more than one of the rows that are prefixed with Kuta,DPS50. exist. Matching on Kuta,DPS50.06, Kuta,DPS50.07, Kuta,DPS50.08, Kuta,DPS50.09, Kuta,DPS50.10.
Assuming all of your records are formatted like: XXX,xxx.###. You can use SUBSTRING_INDEX to parse the prefixed text (Kuta,DPS50.) to use as an identifier.
Then you can use a derived JOIN to match the codes that have duplicates of the prefixed values and update the matching rows.
If there are no duplicate values, no update will occur.
Example: http://sqlfiddle.com/#!9/658034/1 (I added an additional entry for Petang,DPS50.02 to demonstrate it works on other prefixed values.)
Query:
UPDATE mytable AS p
JOIN (
SELECT SUBSTRING_INDEX(code, '.', 1) AS prefix_code
FROM mytable
GROUP BY prefix_code
HAVING COUNT(prefix_code) > 1
) AS c
ON c.prefix_code = SUBSTRING_INDEX(p.code, '.', 1)
SET p.tariff_diff = 1;
Result:
| code | tariff_diff |
|-----------------------|-------------|
| Abiansemal,DPS50.02 | 0 |
| Kuta,DPS50.06 | 1 |
| Kuta,DPS50.07 | 1 |
| Kuta,DPS50.08 | 1 |
| Kuta,DPS50.09 | 1 |
| Kuta,DPS50.10 | 1 |
| Kuta Selatan,DPS50.05 | 0 |
| Kuta Ultara,DPS50.04 | 0 |
| Mengwi,DPS50.01 | 0 |
| Petang,DPS50.02 | 1 |
| Petang,DPS50.03 | 1 |
This will also avoid the SQL Error (1093) https://dev.mysql.com/doc/refman/5.6/en/update.html
You cannot update a table and select from the same table in a subquery.

Issue updating in MySQL where the count of selected rows is 1

I am having a problem updating a table with a simple update statement.
The data looks like this
+----------------------------------------------------------------------+
| id | contractor_id | domain | primary_domain |
_______________________________________________________________________|
| 1 | 50 | foo.com | 1 |
|----------------------------------------------------------------------|
| 2 | 50 | foo.net | 0 |
|----------------------------------------------------------------------|
| 3 | 100 | widget.com | 0 |
+----------------------------------------------------------------------+
What I am trying to do is update only contractors that have 1 domain and that domain is set to 0 ... So in this case it would ignore contractor 50 and set contractor 100's primary_domain to 1
This is what I've come up with, but it's failing and I am not sure why -- Can someone explain my short-coming? How do I achieve the intended result?
UPDATE domains_test SET primary_domain = '1'
WHERE(
SELECT primary_domain
FROM domains_test
WHERE primary_domain = 0
HAVING domain = 1);
EDIT
I have even tried HAVING count(domain) = 1);
The response is always
You can't specify target table 'domains_test' for update in FROM clause
To correctly get the contractor_id values related to just one domain you can use the following query:
SELECT contractor_id
FROM domains_test
GROUP BY contractor_id
HAVING COUNT(DISTINCT domain) = 1;
Output:
contractor_id
--------------
100
So, the UPDATE can be written as:
UPDATE domains_test
SET primary_domain = 1
WHERE primary_domain = 0 AND
contractor_id IN (SELECT contractor_id
FROM (
SELECT contractor_id
FROM domains_test
GROUP BY contractor_id
HAVING COUNT(DISTINCT domain) = 1) AS t);
The nesting in the subquery is necessary due to the error:
you can't specify target table 'domains_test' for update in FROM clause
This error appears in case contractor_id is obtained directly from domains_test in the subquery.
Demo here
SQL DEMO
UPDATE domains_test AS d
LEFT JOIN
(SELECT contractor_id
FROM domains_test
GROUP BY contractor_id
HAVING COUNT(*) = 1) as f
ON d.contractor_id = f.contractor_id
SET d.primary_domain = 1
WHERE d.primary_domain = 0
AND f.contractor_id IS NOT NULL;
Your logic is off-colour: You want to update domains where the COUNT of a subquery is a certain value; in this case, where a count of contractors with only 1 domain and that domain is of 0 value.
you currently do not count anything in your SQL. Instead use this:
UPDATE domains_test SET primary_domain = 1
WHERE (
SELECT COUNT(*) FROM domains_test
GROUP BY (contractor_id)
) = 1
AND primary_domain = 0
What this does: First it searches for groups of contractors where the contractor_id occurs only once in the count, and then for each on of these it checks the value of primary_domain, updating as appropriate when both conditionals are true.

MySql, after DELETE update a counter to contain no gaps

I have a mySql table like this (simplified)
Id*| Text | Pos (integer)
-----------
A | foo | 0
B | bar | 1
C | baz | 2
D | qux | 3
Now, after I delete a row, I want to update the Pos value on the remaining rows so that no "holes" or gaps are to be found.
For example if I row with Id='C' is deleted, the remaing table should be:
Id*| Text | Pos (integer)
-----------
A | foo | 0
B | bar | 1
D | qux | 2
Is this possible in a single query?
UPDATE
Based on the accepted answer this was the solution to my problem:
START TRANSACTION;
SELECT #A:=pos FROM table_name WHERE Id= 'C';
DELETE FROM table_name WHERE Id = 'C';
UPDATE table_name SET Pos = Pos - 1 WHERE Pos > #A;
COMMIT;
You can achieve this by creating a AFTER DELETE TRIGGER on table,
or by using transactions:
START TRANSACTION;
SELECT Pos
INTO #var_pos
FROM table_name
WHERE id = 'C';
DELETE
FROM table_name
WHERE id = 'C';
UPDATE table_name
SET Pos = Pos - 1
WHERE Pos > #var_pos;
COMMIT;
I think this should work, (I haven't tested it)
you can run this statement after any delete
update t set t.Pos=a.iterator
from tablename t
join(
SELECT #i:=#i+1 AS iterator, t.id
FROM tablename t,(SELECT #i:=0) r)a
on a.id=t.id