Selecting row with max date from multiple almost identical tables - mysql

If I can retrieve the most recent name for each id from a table in a MySQL database like so:
SELECT n.id, n.name, n.date
FROM $table AS n
INNER JOIN
(SELECT id, MAX(date) AS date
FROM $table GROUP BY id)
AS max
USING (id, date);
How could I retrieve the most recent name from three almost identical tables (call them $table, $table2, $table3)? They all share the same column structure and the id found from one table may or may not be present in the other two. Think of it as one large table split into three (but with two of them containing two extra columns that are irrelevant in this instance). Would UNION be the best solution? If so, is there a way to do it without a mile-long query?
Constraint:
id is not an auto-incrementing unique integer unfortunately

You can use union all. One slight simplification is the group_concat()/substring_index() trick:
select id, max(date) as date,
substring_index(group_concat(name order by date desc), ',', '') as MostRecentName
from (select t.* from $table1 t union all
select t.* from $table2 t union all
select t.* from $table3
) t
group by id;
This does make certain assumptions. The name cannot contain , (although it is easy enough to change the separator. In addition, the intermediate result for the group_concat() cannot exceed a certain threshold (which is determined by a user-settable system parameter).

You could try:
SELECT n.id, n.name, n.date
FROM table1 where id in (select max(id) from table1)
union
SELECT n.id, n.name, n.date
FROM table2 where id in (select max(id) from table2)
union
SELECT n.id, n.name, n.date
FROM table3 where id in (select max(id) from table3)
Every inner query selects the highest id from the table and then searches for the corresponding fields in the outer query.

This ended up being the only solution I could think of:
SELECT n.id, n.name, n.date FROM (
SELECT id, name, date FROM $table
UNION ALL
SELECT id, name, date FROM $table2
UNION ALL
SELECT id, name, date FROM $table3
) AS n INNER JOIN (
SELECT id, MAX(date) AS date FROM (
SELECT id, date FROM $table
UNION ALL
SELECT id, date FROM $table2
UNION ALL
SELECT id, date FROM $table3
) AS t
GROUP BY id
) AS max USING (id, date)

Related

SQL - Order By Sum of Multiple Tables Sharing Common Field

I have 2 different tables sharing the same column names. The tables list the same products which are identified by 'id'. The products have different revenues throughout both tables and are listed multiple times in each table.
I would like to sum the revenue of the same products across the 2 tables and ORDER BY the sum. Result is sorting the highest revenue products first.
I've tried JOIN and UNION but can't seem to figure out the right solution.
UNION query I tried...
SELECT id, SUM(rev) as total
FROM (
SELECT id, rev FROM table1 UNION ALL
SELECT id, rev FROM table2 UNION ALL
)
ORDER BY total DESC
JOIN query I tried...
SELECT table1.id,
table1.rev,
table2.id,
table2.rev,
(table1.rev + table2.rev) as revenue
FROM table1
INNER JOIN table2 ON table1.id = table2.id
ORDER BY revenue DESC
You were close. You needed:
one UNION ALL, not two.
a GROUP BY, that gives the break field.
An alias for the subquery (I used AllRevenue - you can use any valid name.)
SELECT id, SUM(rev) as total
FROM (
SELECT id, rev FROM table1 UNION ALL
SELECT id, rev FROM table2
) AS AllRevenue
GROUP BY id
ORDER BY total DESC
The join approach would have worked if you used a FULL OUTER JOIN, because some ids may be present in one table but not the other, but that is usually less performant.
Looks like you just need to group on the ID then... unless I'm missing something.
select d.* from (
SELECT
table1.id,
Sum(table1.rev) + Sum(table2.rev) as revenue
FROM table1
INNER JOIN table2 ON table1.id = table2.id
GROUP BY
table1.id) d
order by d.revenue
SELECT id, SUM(rev) as total
FROM (
SELECT id, rev FROM table1 UNION ALL
SELECT id, rev FROM table2
)
GROUP BY id
ORDER BY total DESC

How to select * from table when group by?

select
OrderNo,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
from
tbl_Assign
group by
OrderNo
I want to select * from table also group by from table. How to do it?
To group by on all columns with a sum you cannot use *, you have to list all of the columns out and every column that isn't a function like Sum must be included in the group by.
So if you have other fields in your database such as OrderName, OrderedBy you can perform a group by like this:
Select
OrderNo,
OrderName,
OrderBy,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
From
tbl_Assign
Group By
OrderNo, OrderName, OrderBy
The following will create one row for every row in the tbl_Assign.
Each row will also show the summary information for the order.
This might not be what you need, but it's useful to understand it anyway.
SELECT T1.*, T2.*
FROM
( select * FROM tbl_Assign ) AS T1
LEFT JOIN ( select
OrderNo,
Sum(QtyIn) as QuantityIn,
Sum(QtyOut) as QuantityOut
from
tbl_Assign
group by
OrderNo
) AS T2
ON T1.OrderNo = T2.OrderNo
Harvey

Avoiding duplicates in mysql query that uses UNION and ORDER BY

I have two tables, lets say table1 and table2 with common columns, id and update_date. I am looking to get the id's and update_date based on latest update_date in descending order. I have used 'union' and 'order by' together which gave the results in descending order of update_date but there are duplicate id's which I am not sure how to get rid of.
My query is like,
(select id,update_date from table1 where [condition])
UNION
(select id,update_date from table2 where [condition])
order by update_date desc;
I can just get rid of the duplicate id's by adding select distinct id from (above query) as temp; but the problem is that I need the update_date too.
Can anyone suggest how to get rid of duplicates and still get both id and update_date information.
Assuming you want the latest update out of duplicates this one should work:
SELECT id, max(update_date) AS last_update
FROM
( (select id,update_date from table1 where [conditions])
UNION
(select id,update_date from table2 where [conditions]) ) both_tables
GROUP BY id
ORDER by last_update DESC
Wrap the query in a DISTINCT block:
SELECT DISTINCT * FROM (
select id,update_date from table1 where [condition]
UNION
select id,update_date from table2 where [condition]
)
order by update_date desc;
Limit the second query's results:
select id, update_date
from table1
where [conditions]
union
select id, update_date
from table2
where [conditions]
and id not in (select id from table1 where [conditions])

Diff value last two record by datetime

I have table with id, item_id, value (int), run (datetime) and i need select value diff betwen last two run per *item_id*.
SELECT item_id, ABS(value1 - value2) AS diff
FROM ( SELECT h.item_id, h.value AS value1, h2.value AS value2
FROM ( SELECT id, item_id, value
FROM table_name
GROUP BY item_id
ORDER BY run DESC) AS h
INNER JOIN ( SELECT id, item_id, value
FROM table_name
ORDER BY run DESC) AS h2
ON h.item_id = h2.item_id AND h.id != h2.id
GROUP BY item_id) AS h3
I believe this should do the trick for you. Just replace table_name to correct name.
Explanation:
Basicly I join the table with itself in a run DESC order, JOIN them based on item_id but also on id. Then I GROUP BY them again to remove potential 3rd and so on cases. Lastly I calculate the difference between them through ABS(value1 - value2).
SELECT t2.id, t2.item_id, (t2.value- t1.value) valueDiff, t2.run
FROM ( table_name AS t1
INNER JOIN
table_name AS t2
ON t1.run = (SELECT MAX(run) FROM table_name where run < t2.run)
and t1.item_id = t2.item_id)
This is assuming you want the diff between a record and the record with the previous run

How to get row count of 2 different tables (and databases) in one query?

I got a database named accounts and account table inside of this database, Also I got the database named players and player table inside of this database.
How can I get a rows count of this two tables in one query?
I've tried this:
SELECT
SUM(`account`.`account`.`id`) AS 'accounts',
SUM(`player`.`player`) AS 'players';
But it doesn't work.
If you need exactly rows count (not sum), than do something like this:
select
(select count(*) from accounts.account) as count1,
(select count(*) from players.player) as count2
or
select count(*) as `count`,"account" as `table` from accounts.account
union all
select count(*) as `count`,"player" as `table` from players.player
A simple UNION operation on two select statements will do:
SELECT COUNT(*), 'Accounts' FROM Accounts.Account
UNION
SELECT COUNT(*), 'Players' FROM Players.Player
And you have to qualify each table with the database name since they're in separate databases.
Try:
SELECT
COUNT(`account`.`id`) AS 'accounts',
COUNT(`player`.`player`) AS 'players'
FROM
`account`,
`player`
SELECT COUNT(*)
FROM (
SELECT Id
FROM accounts.account
UNION ALL
SELECT player
FROM players.player ) AS BothTables
with Value (nbr, name ) as
(
select count(*) amount, 'AccountsCount' as ab from accounts..account
union all
select count(*) amount, 'PlayersCount' as ab from players..player
)
select *
from value as s
PIVOT(sum(nbr) for name in (AccountsCount, PlayersCount) ) as pvt