only select row with later expiry date - mysql

if I have a table like the following, how could I only select out those serial_number and its contract_type with later expiry date?
serial_number contract_type expiry_date
abc001 SPRT 2011-05-31 00:00:00
abc001 HOMD 2013-05-31 00:00:00
abc002 SPRT 2012-10-14 00:00:00
abc002 HOMD 2011-10-14 00:00:00
abc003 SPRT 2014-05-31 00:00:00
abc003 HOMD 2011-05-31 00:00:00
................
1) I could make the assumption if it makes this query simpler: each serial_number(SN) will have two and only two contract_types in the table.
2) the actual situation is: SN and contract_type are the primary key, and I'm only looking for the contract_type 'SPRT' and 'HOMD'.
The final result set I need is:
SN with only 'SPRT' or 'HOMD' contract_type
if SN has both 'SPRT' and 'HOMD', I only need the SN's record with later expiry date (if they have the same expiry date, only pick one)
Anyone could give out the query? the actual case might be too complicated to get in one query, but how about the first simplified case.

SELECT t.serial_number, t.contract_type, t.expiry_date
FROM YourTable t
INNER JOIN (SELECT serial_number, MAX(expiry_date) AS MaxDate
FROM YourTable
WHERE contract_type IN ('SPRT', 'HOMD')
GROUP BY serial_number) q
ON t.serial_number = q.serial_number
AND t.expiry_date = q.MaxDate
WHERE t.contract_type IN ('SPRT', 'HOMD')

Related

MySQL multiple sums, using numbers from multiple tables

Let's say I have two tables, one storing accounts, one storing transactions :
id acct_name opening_bal
1 checking 1029.99
2 savings 2002.19
...
And
id date amount from_acct to_acct
...
99 2018-01-21 12.15 1 2
100 2018-01-21 9.99 4 1
101 2018-01-23 10.01 5 2
...
For example, row 99 in the transactions table is saying that 12.15 was transfered from checking to savings on 21 Jan 2018.
I would like to write a query that returns all accounts together with their balances on a given date (like today or 12 Oct 2018, etc), something like this :
acct balance
checking 1599.21
savings 2221.99
...
How would I write such a query?
Edit: Here's a solution, which is close enough to what I want (it just has an additional id column). You can replace CURDATE() with an arbitrary date to get the corresponding table of balances on that date.
SELECT id, acct_name, opening_bal+amt-amt2 as balance FROM accounts
INNER JOIN
(SELECT to_acct, sum(amount) AS amt
FROM transactions
WHERE date <= CURDATE()
GROUP BY to_acct) as T2
ON accounts.id=T2.to_acct
INNER JOIN
(SELECT from_acct, sum(amount) AS amt2
FROM transactions
WHERE date <= CURDATE()
GROUP BY from_acct) as T3
ON T2.to_acct = T3.from_acct
;
Something like this. If you'd provided more data, answer could be more precise. Table1 is your first table, Table2 is the second.
select acct_name as acct,
opening_bal - t1.put_money + t2.get_money as balance
from Table1
left join (select from_acct, ifnull(sum(amount),0) as put_money from Table2 group by from_acct) t1
on t1.from_acct = Table1.id
left join (select to_acct, ifnull(sum(amount),0) as get_money from Table2 group by to_acct) t2
on t2.to_acct = Table1.id;

SQL Duplicate Count if Customer has Spent on Specific Date and Returned?

I've spent a fair amount of time trying to get my head round how to do this, and I can't. I'm making it far to complicated for myself, I understand the code, just not how it all flows together.
If I have table "Customers" with columns for "customer_id", "store_id", "visited", and "date" - I want to identify Customers who visited (visited = yes) a specific store (store_id="NEA") on a set date "2015-05-14" - and then have returned to the same store since then, and count the number of customers who have returned - can anyone help me out?
I know I would need to select customer_id for those who have a store_id of "NEA", a date of "2015-05-14" and a "yes" for visited, but how do I then identify those who returned, and count them - so how many customers visited on that day and then returned?
So for example:
customer_id | store_id | date | visited
123 NEA 2015-05-14 yes
456 NEA 2015-05-14 yes
789 ABC 2015-05-16 no
123 NEA 2015-05-14 yes
654 TDF 2015-05-12 yes
987 PEH 2015-05-14 yes
123 NEA 2015-05-14 no
456 NEA 2015-05-17 yes
987 LEA 2015-05-14 yes
159 NEA 2015-05-16 yes
123 NEA 2015-05-19 yes
or something like this:
SELECT count(*) AS cnt,t.*
FROM yourTable AS t
WHERE
`date` = '2015-05-14'
AND
store_id = 'NEA'
AND
visited = 'YES'
GROUP BY customer_id
HAVING cnt >1;
SELECT DISTINCT customer_id, date
FROM Customers
WHERE visited = 'yes'
GROUP BY customer_id, store_id, date
HAVING COUNT(*) >= 2
Follow the link below for a running demo:
SQLFiddle
The above query yields a list of duplicate customers and the dates on which they visited the same store twice or more. If you want a count of duplicate customers by date, you can wrap it and subquery:
SELECT t.date, COUNT(*) AS duplicateCount
FROM
(
SELECT DISTINCT customer_id, date
FROM Customers
WHERE visited = 'yes'
GROUP BY customer_id, store_id, date
HAVING COUNT(*) >= 2
) t
GROUP BY t.date
SQLFiddle
Update:
Based on your feedback, the following query might be what you had in mind:
SELECT DISTINCT customer_id
FROM Customers
WHERE visited = 'yes'
GROUP BY customer_id, store_id
HAVING SUM(CASE WHEN date = '2015-05-14' THEN 1 ELSE 0 END) >= 1 AND
SUM(CASE WHEN date > '2015-05-14' THEN 1 ELSE 0 END) >= 1

Get highest value for each date

I have a table that logs every time a user completes a survey. It looks a bit like this:
surveyID author timestamp
-----------------------------------------------
1 person1 1461840669000
2 person2 1461840670000
3 person1 1461840680000
I'm trying to run a query that shows me the top surveyor every day (i.e. the person that does the highest number of surveys per day) since April 1st.
So far I've tried this:
SELECT author,
COUNT (DISTINCT surveyid) AS num_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM myTable
WHERE creation_time > 1459468800000 //since April 1st
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;
Which gives me this result:
author num_surveys date
------------------------------------
user1 116 2016-04-27
user2 109 2016-04-27
user3 99 2016-04-27
user3 102 2016-04-28
user1 98 2016-04-28
user2 97 2016-04-28
However, I would really just like the top record from each day:
author num_surveys date
------------------------------------
user1 116 2016-04-27
user3 102 2016-04-28 etc...
I've tried MAX() and TOP() in various places but none of them have worked so far hence the above example of my query that gets me closest to what I want... Any suggestions would be much appreciated. I'm very new to SQL!
EDIT
Thanks for the suggestions to far. Have managed to get it to work with:
DEFINE INLINE TABLE A
SELECT author,
COUNT (DISTINCT featureid) AS num_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM placesense.surveys
WHERE creation_time > 1459468800000
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;
SELECT
MAX(num_surveys),
date
FROM A AS B
WHERE date = B.date
GROUP BY date
Any other more efficient suggestions welcome though.
A pretty simple way uses a correlated subquery:
select t.*
from t
where t.num_surveys = (select max(t2.num_surveys) from t t2 where t2.date = t.date);
Note: this will return duplicates for a date in the case of ties.
SELECT MAX( surveyid) AS m_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM myTable
WHERE creation_time > 1459468800000 //since April 1st
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;

MySQL subquery for selecting latest items returns to much entities

I'm busy with this problem for hours now. I hope you can help me.
I have a table which contains some articles on different inventory locations. There's also a column which describes the date when the current state was noticed.
I try to get a query which returns the entitys of
- a specific article
- for every inventory location
- only one entry for every inventory location, but it should be the latest entry of a specific date.
So, this is my table:
CREATE TABLE `article_stock` (
`id` bigint(20) NOT NULL,
`stock` double NOT NULL,
`date` datetime DEFAULT NULL,
`inventory_location` varchar(255) DEFAULT NULL,
`article` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_krgmyglif194cjh9t1ndmse6n` FOREIGN KEY (`article`)
REFERENCES `article` (`article`)
);
So, I tried several approaches. But I can't solve my problem.
One more example:
I use this query:
SELECT * FROM article_stock WHERE article_stock.date <= "2015-10-12 00:00:00" AND article_stock.article = 5656
id stock date inventory_location article
6310 1058.68 2015-10-10 00:00:00 A64 5656
6311 561.08 2015-10-11 00:00:00 A64 5656
6312 140.92 2015-10-12 00:00:00 A64 5656
6314 20.06 2015-10-10 00:00:00 K16 5656
6315 600 2015-10-11 00:00:00 K16 5656
I want to get the IDs 6312 and 6315.
Can someone help me? :-(
Thank you! :-)
EDIT:
It seems like it's the same problem as described here:Retrieving the last record in each group
But that's not true.
The question there is to retreive the latest record. But I want to get the latest record of a specific date FOR EVERY grouped element...
Let me explain:
I changed the most popular solution for fitting in my situation:
select
a.*
from
article_stock a
inner join
(select inventory_location, max(date) as datecol
from article_stock
WHERE date <= "2015-10-11 00:00:00"
group by inventory_location) as b
ON (a.inventory_location = b.inventory_location
AND a.date = b.datecol)
WHERE article = 5656;
It returns two rows:
id stock date inventory_location article
6311 561.08 2015-10-11 00:00:00 A64 5656
6315 600 2015-10-11 00:00:00 K16 5656
But when I change the date in the where clause to 2015-10-12 it returns only one single row:
id stock date inventory_location article
6312 140.92 2015-10-12 00:00:00 A64 5656
But the correct solution would be:
id stock date inventory_location article
6312 140.92 2015-10-12 00:00:00 A64 5656
6315 600 2015-10-11 00:00:00 K16 5656
I can't assume that every "inventory_location" change happened on the same date! :-(
Think your later query is almost there, but you need to check the article number in the sub query as well (ie, I presume the max date for an inventory location may be different between different articles):-
SELECT a.*
FROM article_stock a
INNER JOIN
(
SELECT article, inventory_location, MAX(`date`) AS max_date
FROM article_stock
WHERE `date` <= "2015-10-12 00:00:00"
GROUP BY article, inventory_location
) b
ON a.article = b.article
AND a.inventory_location = b.inventory_location
AND a.`date` = b.max_date
WHERE a.article = 5656

Selecting latest rows in subgroups

I have the following table created by a join and some conditionals:
product_id date
11111 2012-06-05
11111 2012-05-01
22222 2011-05-01
22222 2011-07-02
33333 2011-01-01
I am trying to get the rows such that I have a result set with the latest date per product:
GOAL
product_id date
11111 2012-06-05
22222 2011-07-02
33333 2011-01-01
I could extract the data as is and do a manual sort, but I'd rather not. I cannot seem to find a way to do a SELECT MAX() without returning only a single row, and I'd rather not run a query for each product id.
The table is generated by this query:
SELECT item_id, sales_price, item, description, transaction_date
FROM db.invoice_line AS t1 INNER JOIN db.invoices AS t2
ON t1.invoice_id = t2.id_invoices WHERE item IS NOT NULL
AND item_id != '800001E9-1325703142' AND item_id != '800002C3-1326830147'
AND invoice_id IN
(SELECT id_invoices FROM db.invoices
WHERE customer_id = '[variable customer id]'
AND transaction_date >= DATE_SUB(NOW(), INTERVAL 360 DAY));
I use a join to 'add' the date column. After that, I disregard useless items, and select from invoices from a particular customer from a year ago to date.
Thanks for any guidance.
Dane
Looks like a group by would fit the bill:
select product_id
, max(date)
from YourTable
group by
product_id