Add New Record Value, & Previous Record Value MySQL - php

I am busy creating a new table in my DB, and have some issues populating the correct values.
The table consists of a number of columns
| Date | CustomerID | SKUCode | NewValueCaptured |PreviousDate| PreviousValueCaptured |
|:----------|:-----------|:--------|:-----------------|:-----------|-----------------------|
| 2022-07-01| 123456 | 1028 | 10 | NULL | NULL |
| 2022-07-09| 123456 | 1028 | 15 | 2022-07-01 | 10 |
| 2022-07-12| 123456 | 1028 | 25 | 2022-07-01 | 15 |
| 2022-07-12| 123456 | 1029 | 8 | NULL | NULL |
| 2022-07-01| 789123 | 1028 | 20 | NULL | NULL |
| 2022-07-09| 789123 | 1028 | 10 | 2022-07-01 | 20 |
| 2022-07-01| 789123 | 1029 | 25 | NULL | NULL |
| 2022-07-09| 789123 | 1029 | 13 | 2022-07-01 | 25 |
Using the UPDATE ON DUPLICATE KEY, is not an option here, as I need to keep each and every record, however, adding only the previous value to the new record.
Existing Query:
INSERT IGNORE INTO CS_data (Date, CustomerID , SKUCode, NewValueCaptured, PreviousDate, PreviousValueCaptured)
SELECT * FROM (SELECT DISTINCT
DWH.Date 'SRCDate'
, DWH.CustomerID
, CASE
WHEN DWH.SKUCode IS NOT NULL THEN DWH.SKUCode
ELSE DWH.SKUCode
END 'SKUCode'
, DWH.ValueCaptured 'SRCValueCaptured'
) SRC
ON DUPLICATE KEY UPDATE
PreviousDate = Date
, PreviousValueCaptured = NewValueCaptured
, Date = SRCDate
, NewValueCaptured= SRCValueCaptured;
How do I achieve the above table results? Rather than updating the existing record.
Thanks

It seems that you need in something like (demo only)
INSERT INTO destination_table (
Date,
CustomerID,
SKUCode,
NewValueCaptured,
PreviousDate,
PreviousValueCaptured
)
SELECT Date,
CustomerID,
SKUCode,
ValueCaptured,
-- get Date value from previous row, if not exists use the value from current row
COALESCE(LAG(Date) OVER (PARTITION BY CustomerID, SKUCode ORDER BY Date),
Date),
-- and the same for ValueCaptured
COALESCE(LAG(ValueCaptured) OVER (PARTITION BY CustomerID, SKUCode ORDER BY Date),
ValueCaptured)
FROM source_table;
Documentation: Window functions.

Related

MySQL issue on INSERT ... SELECT ON DUPLICATE KEY UPDATE and LAST_INSERT_ID()

In MySQL, I have INSERT ... SELECT ON DUPLICATE KEY UPDATE query as below:
$sql = "INSERT INTO user ( name
, mobile
, email
, sex
, username
, password
)
SELECT u.name
, u.mobile
, u.email
, u.sex
, u.username
, u.password
FROM import_user u
WHERE u.name <> '' AND u.mobile <> ''
ON DUPLICATE KEY UPDATE
user_id = LAST_INSERT_ID(user_id),
name = VALUES (name),
mobile = VALUES (mobile),
email = VALUES (email),
sex = VALUES (sex)";
UPDATE:
This is the result from above query.
select user_id, role_id, name,sex, mobile from user;
+---------+---------------------------+--------+-------------+
| user_id | name | sex | mobile |
+---------+---------------------------+--------+-------------+
| 131 | Name 1 | Male | 435345345 |
| 132 | Name 2 | Male | 43543534 |
| 133 | Name 3 | Male | 45645644 |
| 134 | Name 4 | Male | 5345 |
| 135 | Name 5 | Male | 5465475 |
| 136 | Name 6 | Male | 56456546 |
+---------+---------------------------+--------+-------------+
Now I want to create an array of the user_id of either the insert or the update the records.
So, my expecting array should be
$uid = [131,132,133,134,135,136]
I tried it something like this, but it doesn't work for me. That mean I can get only one id.
$stmt = $pdo->prepare($sql);
$stmt->execute();
$uids[] = $pdo->lastInsertId();
So, May I know Is there a way to create an array from the effected user ID of the above query running?
DEMO:
CREATE TABLE test (id INT AUTO_INCREMENT PRIMARY KEY,
category INT,
value INT,
UNIQUE (category, value) );
CREATE TRIGGER tr_ai
AFTER INSERT ON test
FOR EACH ROW
SET #ids_array := CONCAT_WS(',', #ids_array, NEW.id);
CREATE TRIGGER tr_au
AFTER UPDATE ON test
FOR EACH ROW
SET #ids_array := CONCAT_WS(',', #ids_array, NEW.id);
SET #ids_array := NULL;
INSERT INTO test (category, value)
VALUES (1,11), (2,22);
SELECT * FROM test;
SELECT #ids_array;
id | category | value
-: | -------: | ----:
1 | 1 | 11
2 | 2 | 22
| #ids_array |
| :--------- |
| 1,2 |
SET #ids_array := NULL;
INSERT INTO test (category, value)
VALUES (1,111), (2,22)
ON DUPLICATE KEY
UPDATE value = NULL;
SELECT * FROM test;
SELECT #ids_array;
id | category | value
-: | -------: | ----:
1 | 1 | 11
3 | 1 | 111
2 | 2 | null
| #ids_array |
| :--------- |
| 3,2 |
-- do not reset #ids_array
INSERT INTO test (id, category, value)
VALUES (1,4,44), (22,2,22)
ON DUPLICATE KEY
UPDATE value = NULL;
SELECT * FROM test;
SELECT #ids_array;
id | category | value
-: | -------: | ----:
1 | 1 | null
3 | 1 | 111
2 | 2 | null
22 | 2 | 22
| #ids_array |
| :--------- |
| 3,2,1,22 |
db<>fiddle here

MariaDB ignores ORDER BY in SELECT

I installed new version of MariaDB and got problem with sorting php-script:
$this->db->query("
SET #v:=0;
UPDATE `users` AS `c1`
LEFT JOIN (SELECT `id`, (#v:=#v+2) AS `ord2`, `name`, `parent`
FROM `users`
WHERE `parent`='0' ORDER BY `ord` ASC) AS `c2`
ON `c1`.`id` = `c2`.`id`
SET `c1`.`ord` = `c2`.`ord2`
WHERE `c1`.`parent` = '0'
");
In particular script sets order of entries in users table sorting them by ord:
+----+-----+--------------------+--------+
| id | ord | name | parent |
+----+-----+--------------------+--------+
| 2 | 2 | admin | 0 |
| 10 | 5 | manager | 0 |
| 12 | 7 | user | 0 |
| 11 | 9 | dev | 0 |
+----+-----+--------------------+--------+
I'm not familiar with SQL and after long hours of searching and tests I, as it seems to me, found out the SQL-query that doesn't work right:
SELECT `id`, (#v:=#v+2) AS `ord2`, `name`, `parent`
FROM `users`
WHERE `parent`='0' ORDER BY `ord` ASC;
In previous version of MariaDB (5.5.5-10.1.25) the query gives entries sorted by initial order (ord):
+----+-----+--------------------+--------+
| id | ord2| name | parent |
+----+-----+--------------------+--------+
| 2 | 2 | admin | 0 |
| 10 | 4 | manager | 0 |
| 12 | 6 | user | 0 |
| 11 | 8 | dev | 0 |
+----+-----+--------------------+--------+
In new version (10.6.3) result is:
+----+-----+--------------------+--------+
| id | ord2| name | parent |
+----+-----+--------------------+--------+
| 2 | 2 | admin | 0 |
| 10 | 4 | manager | 0 |
| 12 | 8 | user | 0 |
| 11 | 6 | dev | 0 |
+----+-----+--------------------+--------+
I tried to set ORDER BY param ord to name and id, but result was the same. It seems like col ord2 filled with even numbers is always sorted by id in ascending order.
How should I rewrite the query or the script to fix the problem?
In latest MariaDB versions you can use window function row_number in next way:
select
id,
(row_number() over (order by ord))*2 ard2,
name,
parent
from tbl;
MariaDB query test here

SQL query to return combined data of all rows that don't belong to current user

Imagine this is my table:
----------------------------------------------------
| id | user_id | amount_1 | amount_2 | amount_3 |
----------------------------------------------------
| 1 | 1 | 2 | 3 | 4 |
----------------------------------------------------
| 2 | 2 | 2 | 1 | 1 |
----------------------------------------------------
| 3 | 2 | 1 | 2 | 2 |
----------------------------------------------------
| 4 | 3 | 2 | 1 | 4 |
----------------------------------------------------
I need a query that gives me one result set for every entry that belongs to my current user, and then returns everything else as a single combined row with the amounts summed.
So in this case if I am user 1, I should get the following rows back:
---------------------------------------
| id | amount_1 | amount_2 | amount_3 |
---------------------------------------
| 1 | 2 | 3 | 4 | my own amounts
---------------------------------------
| 2 | 5 | 4 | 7 | everyone else's amounts
---------------------------------------
Any tips?
I've considered it might be a better idea to just filter the data in the code (php). Please help i'm starting to hate myself
You could use a UNION in sql
select 1 id, amount_1, amount_2, amount_3
from my_table
where user_id = 1
union
select 2 , sum(amount_1) , sum(amount_2), sum(amount_3 )
from my_table
where user_id <> 1
You can do with one query using union:
SELECT user_id, amount_1, amount_2, amount_3
FROM table
WHERE user_id = YOUR_USER_ID
UNION
SELECT -1, SUM(amount_1) AS amount_1, SUM(amount_2) AS amount_2, SUM(amount_3) AS amount_3
FROM table
WHERE user_id != YOUR_USER_ID
You can use aggregation in one fell swoop:
select (case when user_id = 1 then id end) as my_user_or_not,
sum(amount_1), sum(amount_2), sum(amount_3)
from t
group by my_user_or_not;
The null values in the first column indicate another user. You have labelled the column id, which is a bit problematic if you were -- for instance -- to choose user_id = 2 in your example. NULL seems safer for this purpose.

Set auto-increments based on hospital ID

My Company has multiple clients. Each client needs to have their own auto increment column.
For example, there are multiple hospitals that need to record their patients' records to my server. And each patient needs to have a reference number. Reference numbers are incrementing.
Here is what I want my table to look like
+-----------+-----------+-----------+----------+
| user_id | names | ref_no | hospital |
+-----------+-----------+-----------+----------+
| 1 |cholo wao | 1 | TMJ |
| 2 |royson ml..| 2 | TMJ |
| 3 |pascal va..| 3 | TMJ |
| 4 |mustafa s..| 1 | MBE |
| 5 |nassoro h..| 4 | TMJ |
| 6 |zunaida s..| 2 | MBE |
| 7 |hadija ma..| 3 | MBE |
| 8 |kulsum za..| 4 | MBE |
| 9 |zawadi ya..| 1 | MSA |
| 10 |khamis mo..| 5 | TMJ |
| 11 |saada hem..| 5 | MBE |
| 12 |mark zuck..| 6 | TMJ |
+-----------+-----------+-----------+----------+
As you have seen above the ref_no only increment based on the last insert ID of a previous Hosptial. I have been told that using MAX(hospital) can cause danger as more than one row may be inserted at a time.
summary QN
Which Query can I use to insert reference number based on the last ID of a particular hospital?
I have seen two solutions in SO about this, make a try
1st one
CREATE temporary table seq ( id int, seq int);
INSERT INTO seq ( id, seq )
SELECT user_id,
(SELECT count(*) + 1 FROM client c
WHERE hospital='TMJ') as seq
FROM client;
UPDATE client INNER join seq ON client.user_id = seq.id SET
client.ref_no = seq.seq;
2nd one
INSERT INTO
client( names, ref_no, hospital )
'cholo wao',SELECT MAX(ref_no) + 1 WHERE hospital='TMJ','TMJ' FROM
client;

MySQL query the same table with two date fields and group by same ID

I'm having a hard time getting results from a DB the way I need them, this is my table:
+----+---------------------+---------------------+-----------+------------+--------+
| id | opendate | closedate | openprice | closeprice | sameid |
+----+---------------------+---------------------+-----------+------------+--------+
| 1 | 2015-09-20 19:17:52 | NULL | 10 | NULL | 20 |
| 2 | NULL | 2015-09-20 20:17:00 | NULL | 35 | 20 |
| 3 | 2015-09-15 19:17:52 | NULL | 15 | NULL | 10 |
| 4 | NULL | 2015-09-16 20:17:00 | NULL | 25 | 10 |
+----+---------------------+---------------------+-----------+------------+--------+
I need to get all the rows grouped by the column sameid like this:
+----+---------------------+---------------------+-----------+------------+--------+
| id | opendate | closedate | openprice | closeprice | sameid |
+----+---------------------+---------------------+-----------+------------+--------+
| 1 | 2015-09-20 19:17:52 | 2015-09-20 20:17:00 | 10 | 35 | 20 |
| 3 | 2015-09-15 19:17:52 | 2015-09-16 20:17:00 | 15 | 25 | 10 |
+----+---------------------+---------------------+-----------+------------+--------+
And this is what I have tried so far:
(SELECT * FROM table WHERE opendate >= '2015-08-08 00:00:01') UNION (SELECT * FROM table WHERE closedate <= '2015-10-15 23:59:59')
I can get all the rows but I can not fin a way to group them by sameid, I tried using GROUP BY sameid without success.
Hope you guys can help me
Thank you
UPDATE
The table was designed that way long ago, (not by me) and there is too much information stored, I'm not allowed to redesign the DB schema either.
If your table format exactly what you describe, then this should work:
SELECT id, MAX(opendate), MAX(closedate), MAX(openprice), MAX(closeprice), sameid FROM table GROUP BY sameid;
However, I think you should redesign your database schema, seperate open info and close info into 2 rows (they could be in 2 tables or in same table). It's would be better for you to work with rather than trying some workaround.
Regards,
Try this
SELECT t1.opendate, t2.closedate, t1.openprice, t2.closeprice FROM `table` t1 JOIN `table` t2 ON t2.sameid = t1.sameid WHERE t1.opendate >= '2015-08-08 00:00:01' AND t2.closedate <= '2015-10-15 23:59:59' AND t1.opendate IS NOT NULL AND t2.closedate IS NOT NULL
This will produce your exact output.
SELECT
MIN(id) as id,
MAX(open_date) as open_date,
MAX(close_date) as close_date,
MAX(open_price) as open_price,
MAX(close_price) as close_price,
sameid
FROM
`table`
GROUP BY
sameid
ORDER BY id ASC

Categories