Select second instance of record ID in mysql table - mysql

I need to be able to find when each customer placed their second order and I can't think of how to do it!
Basic table structure:
Order ID Customer ID Order Date
1 123 2014-09-12
2 456 2014-10-22
3 456 2014-11-01 <-- THIS IS CUST 456's 2ND ORDER
4 789 2014-11-01
5 123 2014-11-09 <-- THIS IS CUST 123's 2ND ORDER
6 225 2014-11-11
How do I get the second orders out of the table using mysql?
The real table has over 200K of orders and over 70K customers, each ranging from only having placed one order to having placed 20+ orders since 2010.

If you just want the 2nd order date then a self join to exclude the first order, and a MIN to get the remaining earliest order:-
SELECT t1.CustomerId, MIN(t2.OrderDate)
FROM
( SELECT CustomerId, MIN(OrderDate) AS OrderDate
FROM some_table
GROUP BY CustomerId
) t1
INNER JOIN some_table t2
ON t1.CustomerId = t2.CustomerId
AND t1.OrderDate < t2.OrderDate
GROUP BY t1.CustomerId
If you need other details (such as the order id) then you would need to use this as a sub query and join it back against the main table.
EDIT - Might be possible to simplify this as follows:-
SELECT t1.CustomerId, MIN(t2.OrderDate)
FROM some_table t1
INNER JOIN some_table t2
ON t1.CustomerId = t2.CustomerId
AND t1.OrderDate < t2.OrderDate
GROUP BY t1.CustomerId
This is joining the table against itself based on the customer id, but also that the order date is larger on the 2nd join of the table.
This is likely to generate a massive amount of data while doing the calculation.
I have a feeling I have missed something with this though.

Related

Not sure how to get this working with respect a SQL query

I have two tables named table1 and table2:
Table1
id date email cId
1 2013-08-28 12:21:39 t#gmail.com 12345
2 2013-07-27 10:15:18 k#gmail.com 12345
3 2018-02-13 09:41:43 a#gmail.com 12345
4 2018-02-02 10:14:42 n#gmail.com 45678
5 2017-11-16 10:16:51 l#gmail.com 45678
Table2
id status
12345 1
45678 1
56789 0
When I execute a query I am expecting to get row from table1 which has max date.
select c.id 'table 2 Id'
, DATE_FORMAT(Max(u.date),'%Y-%m-%dT%TZ') 'Date'
, u.email 'User'
from table2 c
LEFT
JOIN table1 u
ON u.cId = c.id
where c.status = 1
group
by c.id
order
by c.id;
How ever what I see is kind of confusing.
table 2 Id Date USER
12345 2018-02-13 09:41:43 t#gmail.com
I am expecting the output to be
table 2 Id Date USER
12345 2018-02-13 09:41:43 a#gmail.com
Because the max date that is selected is not same of the user t#gmail.com but of a#gmail.com
Any suggestions on where has it gone wrong and how can I tweak it to get correct result?
The moment you use a grouping function (i.e. max, sum, count, etc.) you must specify only segregating columns in the SELECT clause.
In your case, there are several emails for one given id, much like the date field.
You can't just specify
SELECT id, max(date), email ...
it wouldn't make sense, because you need to specify a grouping function for the mail.
What you're really interested in, is "the email that corresponds to the row whose date is max(date) for a given id".
This must be done using a subquery. Something like this:
SELECT
tmax.cid,
tmax.maxdate,
table1.email,
table2.status
FROM
table2
INNER JOIN table1
ON table1.cid = table2.id
INNER JOIN (
SELECT
cid,
max(date) AS maxdate
FROM
table1
GROUP BY
cid
) AS tmax
ON tmax.cid = table1.cid AND tmax.maxdate = table1.date;
The above query executed on your data set, will give this exact output (2 rows):
cid maxdate email status
12345 2018-02-13 09:41:43 a#gmail.com 1
45678 2018-02-02 10:14:42 n#gmail.com 1
which means, in English: "For each id in table2, bring its status, and bring the line in table1 for the corresponding cid, and whose date is the max date for same cid within table1."
Because I used INNER JOINs, the records in table1 that mention a cid that does not exist in table2, are discarded.
You could write the query like this (add an order desc on u.date):
SELECT c.id 'table 2 Id', DATE_FORMAT(MAX(u.date),'%Y-%m-%dT%TZ') 'Date', u.email 'User'
FROM table2 c
LEFT JOIN table1 u ON u.cId = c.id
WHERE c.status = 1
GROUP BY c.id
ORDER BY c.id, u.date DESC;

SQL Join 2 tables with "ON" on max value in second table

I have 2 tables one with inventory and other with prices list on different dates. I need to update table 1 with price on a particular date which may not be available in table 2 so i need to lookback on last available price. How can I do this. Following are my tables:
Table1
SrNo Commodity Date Price
1 Car 20-Aug-2015 <115>
2 Cycle 20-Aug-2015 <78>
Table2
SrNo Commodity Price Date
1 Car 100 1-Jan-2015
2 Car 120 1-Jun-2015
3 Car 115 20-Aug-2015
4 Cycle 80 10-May-2015
5 Cycle 78 10-Jun-2015
I tried using an inner join but I could get it for Car since it has an entry on 20-Aug-2015. I want cycle to be shown as 78 as it was the last available price.
Can someone suggest me how to do this.
Thanks,
Swati
Next code will work on T-SQL - try so
update t1 set
t1.Price = t2.Price
from Table1 as t1
outer apply (
select top 1
t2.Price
from Table2 as t2
where t2.SrNo = t1.SrNo
order by t2.Date desc
) t2
Try this:
UPDATE a
SET a.Price = b.Price
FROM Table1 a
INNER JOIN Table2 b ON a.Commodity = b.Commodity
WHERE b.[Date] = (SELECT MAX([Date])
FROM Table2 c
WHERE b.Commodity = c.Commodity
AND c.[Date] <= a.[Date]
GROUP BY c.Commodity)
For MySql
UPDATE Table1
JOIN ( SELECT Commodity,Price
FROM Table2 JOIN (SELECT Table2.Commodity,MAX(DATE) As LastDate
FROM Table2
GROUP BY Commodity ) AS Tmp1
ON Table2.Date = Tmp1.LastDate
) AS Tmp2
ON Tmp2.Commodity = Table1.Commodity
SET Table1 .Price = Tmp2.Price
MAX(DATE) is calculated in inner query Tmp1 to get last availaible price of commodity
SQLFiddle Demo

Joining 2 tables and adding price to give total revenue in MySQL

probably a simple query for someone to answer but I'm new at this and a bit stuck!
Trying to map from one table to another and sum together numbers in a column from Table 1. For example:
Table 1:
Item_ID Price
I0001 3.50
I0002 2.50
Table 2:
Item_ID Date_sold
I0001 10/11/14
I0002 12/11/14
What I want to do is tell MySQL that where 'Date_sold' is 'not null' in Table 2, to identify 'Item_id', match this back to table 1, read the 'Price' column in that row, and then add the results together for total revenue.
Any help appreciated!
I ll try something like that :
SELECT t1.Item_ID, SUM(Price) AS Total
FROM Table1 t1
INNER JOIN Table 2 t2
ON t1.Item_ID = t2.Item_ID
WHERE t2.Sold_date IS NOT NULL
GROUP BY Item_ID;
You will get the grand total by item if you add the group by statement.
If you only want the grand total :
SELECT SUM(Price) AS GrandTotal
FROM Table1 t1
INNER JOIN Table 2 t2
ON t1.Item_ID = t2.Item_ID
WHERE t2.Sold_date IS NOT NULL;
You could join both tales on the item_id, and then group by to sum the price:
SELECT date_sold, SUM(price)
FROM table_2
JOIN table_1 on table_2.item_id = table_1.item_id
WHERE date_sold IS NOT NULL
GROUP BY date_sold
select sum(table1.price) as revenue from table1 join table2 on table1.item_id=table2.item_id where table2.data_sold is not null

multiple GROUP BY to find more than one row based on WHERE condition

I have a table for timetable allocation for an institution. I have to figure out if there are more than one allocations in the same room in a single period meaning there shouldn't be any room with more than one allocation for a particular period.
Table structure with relevant fields for this question is as follows:
teacherid subjectid groupname room day period
1 213 2 1 4 3
2 123 4 1 5 3
and so on...
How can return those rooms with more than one allocations in a single period.
select distinct room from table t1 where exists
(select count(*) c1 from table where t1.room = room
and t1.day=day and t1.period = period having c1>1);
If day need not to be considered:
select distinct room from table t1 where exists
(select count(*) c1 from table where t1.room = room
and t1.period = period having c1>1);
select t1.room
from timetable t1
join timetable t2
on t1.day = t2.day
and t1.period = t2.period
and t1.id > t2.id
The join is fairly straightforward - it finds rows with the sane day/period, but there is a trick in there worth noting... the last comparison in the join condition:
and t1.id > t2.id
This does two things:
Stops rows joining to themselves
Stops colliding rows from joining twice. Without the greater-than (or a less-than would work equally well) ie if it was !=, colliding rows would join once for each side of the join
You asked for just the rooms, but if you select * you'll get all the info about the collision.

MySQL, summing certain rows from a hash table, using results from a subquery

I'm trying to sum certain rows from a hash table using two elements: a select group of IDs and a particular key.
Here's the setup:
Table 1:
ID KEY VALUE
1 name John Doe
1 amount 10
2 name Jane Doe
2 amount 15
3 name Mike Lowry
3 amount 5
Table 2:
ORDERID TYPE TRANSACTIONID
1001 Purchase 1
1002 Donation 2
1003 Purchase 3
I'm trying to get a sum of all the amounts where the type is "Purchase." Here's the query I'm using:
SELECT SUM(Table1.value) as balance
FROM Table1
LEFT JOIN (SELECT Table2.TRANSACTIONID as TID FROM Table2 WHERE Table2.TYPE = "Purchase" ) as ids
ON Table1.ID = ids.TID
WHERE Table1.key = "amount"
Tweaking that, I've managed to get 0 and the total of all the rows, but not just the one result. Ideas?
The problem is that your query makes an outer join between Table1 and Table2, such that all records of Table1 are preserved irrespective of whether a matching record is found from Table2. Learn about SQL joins.
You want to make an inner join instead:
SELECT SUM(VALUE)
FROM Table1 JOIN Table2 ON Table1.ID = Table2.TRANSACTIONID
WHERE Table1.KEY = 'amount' AND Table2.TYPE = 'Purchase'
See it on sqlfiddle.