Select row based on max date across several columns - mysql

For a mysql database
I have a table which includes duplicate rows because of date values in several columns. I am looking to select a single row for each unique customer id based on a max date value evaluated across several date columns
[customer id, startDate, StopDate, modifyDate, buyDate]
For each customer id, i'd like to return the row that has the maximum date either in the startDate, StopDate, modifyDate or buyDate columns ( there are some nulls in the date columns.
editing to include example - but to sure how to create a table here:
*** Edit
Been trying for quite awhile now to create a table here with an example. can't figure out. So posting an image? the desired rows to the returned indicated in red.

Assuming that the values are never NULL, you can use greatest():
select t.*
from table t
where greatest(t.startDate, stopDate, buyDate) =
(select max(greatest(t.startDate, stopDate, buyDate))
from t t2
where t2.customerid = t.customerid
);
Note: this will return multiple rows for a customer if more than one row contains the maximum date.

Related

MYSQL Delete all rows with the minimum DATE value

In MYSQL, I have a dataset which contains stock data of many many dates, and I want to delete all the rows that have the lowest date value (my date value is an integer, so in other words, I want to delete trades from the first date). I have found this code on stack overflow, but it only deletes one row, while I want to delete ALL rows with this minimum date.
This is the code I have found.
DELETE FROM TABLE
ORDER BY DATE
LIMIT 1
Thank you!
Use a query to find out minimum date then delete all records for this date.
-- MySQL
DELETE t
FROM TEST_TRADES t
INNER JOIN (SELECT MIN(COB_DATE) a
FROM TEST_TRADES) tt
ON t.COB_DATE = tt.a
Please check from url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=4262ea268d2d9ba9b617142edf536cdc
I found solution to this question:
This is what I've done:
SELECT #MIN_DATE := MIN(DATE) FROM TABLE T;
DELETE FROM TABLE WHERE T.DATE = #MIN_DATE

counting all records in table and putting it into a variable inside mysql itself

I have a table named financial_trans which consist of
id (AI,INT)
amount (DOUBLE)
acadYear (VARCHAR) // probably '2020-2021'
now I want to count the similar acadYear using group by and store it into a mysql variable and my query for that is
SELECT s.total as total
INTO #year
FROM (
SELECT COUNT(acadYear) as total
FROM financial_trans
GROUP BY acadYear
) s
but throws an error like below,
#1172 - Result consisted of more than one row
Your sub-statement SELECT COUNT(acadYear) as total FROM financial_trans GROUP BY acadYear yields more then 1 row, so it can fit into variable #year.
That basically means that you have records for more then 1 distinct year in your financial_trans table. If you need to count records only for specific year, just add WHERE acadYear = XXXX into subquery. Or even better, SELECT COUNT(1) FROM financial_trans WHERE acadYear = XXXX.
Side note: DOUBLE is not ideal column type for financial records, you should use DECIMAL

MySQL - DATEDIFF LOOKUP previous row (same ID)

I'm trying to create an extra column on my SQL where I could identify if the user_id generated a subsequent (or even third) row.
And if so, calculate the datediff between the connection time and previous row disconnection time.
If no duplicate user_id, the response should be NULL.
Here's a screenshot of my data and notes:
I tried the DATEDIFF formula but no success.
Could someone help me on this? I really would appreciate any input.
SELECT id,
user_id,
connected_at,
disconnected_at,
IFNULL(DateDiff('second', Lookup(disconnected_at), -1), connected_at)
FROM data
ORDER BY id, user_id, connected_at
When comparing values in different rows, you need to join the table to itself to get the second row. Try this:
SELECT
a.id,
a.user_id,
a.connected_at,
a.disconnected_at,
DateDiff('second',b.`connected_at`,a.`disconnected_at`) as `time_diff`
FROM `data` a
JOIN `data` b
ON a.`user_id` = b.`user_id` AND b.`connected_at` > a.`disconnected_at`

Fast MAX, GROUP BY on the concatenation of mulliple columns

I have a table with 4 columns: name, date, version,and value. There's an composite index on all four, in that order. It has 20M rows: 2.000 names, approx 1.000 dates per name, approx 10 versions per date.
I'm trying to get a list that give for all names the highest date, the highest version on that date, and the associated value.
When I do
SELECT name,
MAX(date)
FROM table
GROUP BY name
I get good performance and the database uses the composite index
However, when I join the table to this in order to get the MAX(version) per name the query takes ages. There must be a way to get the result in about the same magnitude of time as the SELECT statement above? I can easily be done by using the index.
Try this: (I know it needs a few syntax tweaks for MySQL... ask for them and I will find them)
INSERT INTO #TempTable
SELECT name, MAX(Date) as Date
FROM table
Group By name
select table.name, table.date, max(table.version) as version
from table
inner join #TempTable on table.name = #temptable.name and table.date = #temptable.date
group by table.name, table.date

MySQL INSERT/SELECT subquery syntax

Just can't wrap my head around the proper syntax for this one. Below is my query, with a plain english explanation of my subquery, in the spot where I think I'd want it to execute.
mysql_query("INSERT INTO donations(
tid,
email,
amount,
ogrequest,
total
)
VALUES (
'".esc($p->ipn_data['txn_id'])."',
'".esc($p->ipn_data['pay_email'])."',
".(float)$amount.",
'".esc(http_build_query($_POST))."',
Here I want to select the row with the max date, get the value of the "total" column in that row, and add $amount to that value to form the new "total" for my newly inserted row.
)");
Can anyone help a bro out?
The real answer is you should not be storing the total in a column in this table. It isn't really any useful information. What you should be storing is the current date, and then calculating the total via SUM and GROUP BY. If it's something that you need to access often, then cache the value elsewhere.
Why do you need the total in any of the rows before the last one? It is just wasted data, and it can be easily regenerated from the table.
Why do you want to store the total in this column. What value does this data add to your schema? The important thing to note here is that the total is NOT a property of the individual transaction. The total is a property of an aggregated subset of individual transactions.
Also - make sure you are using DECIMAL and not FLOAT for your monetary column types in MySQL if you aren't. FLOAT values could result in rounding errors depending on what you are doing, which is something there is no reason to risk when money is involved.
I don't have access to a MySQL server to verify what I created, but try this:
INSERT INTO donations
(
tid,
email,
amount,
ogrequest,
total
)
SELECT
'".esc($p->ipn_data['txn_id'])."',
'".esc($p->ipn_data['pay_email'])."',
".(float)$amount.",
'".esc(http_build_query($_POST))."',
total + '".esc($amount)."'
FROM
ORDER BY date DESC
LIMIT 1
Instead of using a direct "INSERT INTO (...) VALUES (...)" I used a "INSERT INTO (...) SELECT ...". The SELECT statement retrieves the row with the highest date (ORDER BY date DESC LIMIT 1), then the total field is accessed and added with the value of $amount.
mysql_query("INSERT INTO donations(
tid,
email,
amount,
ogrequest,
total
)
VALUES (
'".esc($p->ipn_data['txn_id'])."',
'".esc($p->ipn_data['pay_email'])."',
".(float)$amount.",
'".esc(http_build_query($_POST))."',
(select max(total) from donations) + ".(float)$amount."
)");
Your subquery could look like this:
SELECT total
FROM donations
WHERE tid = <x>
ORDER BY date DESC
LIMIT 1
This of course requires that you have a date column in your table. If you run this one (without the outer query you already have), it should come back with a single row, single column result containing the value of latest total for tid = <x>.
If there's not already a row for txn = <x> in the table, then it will obviously return no row at all. When used as a subquery for your INSERT statement, you should probably check for NULL and replace it with a numeric 0 (zero). This is what IFNULL() can do for you.
Combining this and what you already have:
mysql_query("INSERT INTO donations(
tid,
email,
amount,
ogrequest,
total
)
VALUES (
'".esc($p->ipn_data['txn_id'])."',
'".esc($p->ipn_data['pay_email'])."',
".(float)$amount.",
'".esc(http_build_query($_POST))."',
IFNULL(SELECT total
FROM donations
WHERE id = ".esc(p->ipn_data[txn_id']."
ORDER BY date DESC
LIMIT 1),0) + ".esc($p->ipn_data['value']
)");