This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 5 years ago.
I have 2 relevant tables here, application and application_note.
I want to find the latest note (user and text/note) for each application.
application_note looks like
+----------------+-------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| create_time | timestamp | NO | | CURRENT_TIMESTAMP | |
| update_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| application_id | int(11) | YES | MUL | NULL | |
| note | text | YES | | NULL | |
| user | varchar(50) | YES | | NULL | |
+----------------+-------------+------+-----+-------------------+-----------------------------+
I've been trying a bunch of different queries. The closest thing I have is
SELECT user, note, application_id, MAX(create_time)
FROM application_note
GROUP BY application_id
which looks like the max(create_time) is what I expect, but the other values are off. I've been trying at this for awhile and have been getting no where.
edit: I plan to eventually add this a view or add this to a larger query, if that changes anything.
You have to join the table back on itself:
SELECT b.application_id, b.ct, a.note, a.user
FROM (SELECT application_id, MAX(create_time) AS ct
FROM application_note
GROUP BY application_id) b
INNER JOIN application_note a ON a.application_id=b.application_id
AND a.create_time=b.ct
This will return the record with the latest creation time for a given application id. Duplicates might occur when you have multiple records with the same creation_time for a given application_id
Related
This question already has answers here:
Delete partially similar rows in MySQL
(3 answers)
Closed 1 year ago.
We have a table with the following schema:
+--------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(128) | YES | | NULL | |
| label | varchar(10) | NO | | NULL | |
| f1 | varchar(8) | YES | | NULL | |
| f2 | varchar(6) | YES | | NULL | |
+--------+------------------+------+-----+---------+----------------+
We would like to consider all rows where the name-label pair is non-distinct to be duplicates (i.e. ignoring f1 and f2). In such cases we would like to delete the duplicate rows by retaining only the row with the highest id (which incidentally would have been entered in the table at a later time, and therefore assumed to be more current).
What would be the most efficient way to realize it in MySQL 5.6.51?
JOIN itself and delete the row with smaller id
DELETE a
FROM duplicates a
JOIN duplicates b ON a.label = b.label AND a.name = b.name
WHERE a.id < b.id
name could be NULL, if NULL is considered duplicate:
DELETE a
FROM duplicates a
JOIN duplicates b ON a.label = b.label AND COALESCE(a.name, '') = COALESCE(b.name, '')
WHERE a.id < b.id
At first, I want to apologize for providing such a weak title; I couldn't describe it in a better way.
Consider the following: We have three tables, one for users, one for records and one for ratings. The tables are quite self-explanatory but the schema for database is as following:
+---------------------+
| Tables_in_relations |
+---------------------+
| records |
| ratings |
| users |
+---------------------+
The schema for records table is as following:
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(256) | NO | | NULL | |
| year | int(4) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
The schema for users table is as following:
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| email | varchar(256) | NO | | NULL | |
| name | varchar(256) | NO | | NULL | |
| password | varchar(256) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
ratings table is, obvoiusly, where the ratings are stored among with the record_id and user_id and works as a relation table.
It's schema is as following:
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| record_id| smallint(5) unsigned | NO | MUL | NULL | |
| user_id | smallint(5) unsigned | NO | MUL | NULL | |
| rating | int(1) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
Now, In my application, I have a search function that fetches records based on a certain keyword. The output should also include the average rating of a certain record and a total amount of ratings per record. This can be accomplished by following query:
SELECT re.id, re.title, re.year, ROUND(avg(ra.rating)) as avg_rate,
COUNT(ra.record_id) as total_times_rated
FROM records re
LEFT JOIN ratings ra ON ra.record_id = re.id
GROUP BY re.id;
which will give me the following output:
+----+------------------------+------+----------+-------------------+
| id | title | year | avg_rate | total_times_rated |
+----+------------------------+------+----------+-------------------+
| 1 | Test Record 1 | 2008 | 3 | 4 |
| 2 | Test Record 2 | 2012 | 2 | 4 |
| 3 | Test Record 3 | 2003 | 3 | 4 |
| 4 | Test Record 4 | 2012 | 3 | 3 |
| 5 | Test Record 5 | 2003 | 2 | 3 |
| 6 | Test Record 6 | 2006 | 2 | 3 |
+----+------------------------+------+----------+-------------------+
Question:
Now, here comes the tricky part, at least for me. Within my app, you can search records whether signed in or not and if signed in, I'd also like to include the user's own rating value in the above query.
I know that I can run a conditional to check whether user is signed in or not by reading the session value and execute a corresponding query based on that. I just don't know how to include that individual rating value of a certain user to the above query.
You can add user's rating in the result by adding a SELECT query in columns:
SELECT re.id, re.title, re.year, ROUND(avg(ra.rating)) as avg_rate,
COUNT(ra.record_id) as total_times_rated,
(SELECT rating FROM ratings WHERE user_id = ? AND record_id = re.id) as user_rating
FROM records re
LEFT JOIN ratings ra ON ra.record_id = re.id
GROUP BY re.id;
We can get the user_id from session and pass it to this query in order to generate user_rating column in the result.
Assuming user can rate a record multiple times, I have used SUM. If not, we can remove it from the query.
Update
If you don't want GROUP BY to consider that value then you can wrap the existing query into another query and add a column to it, e.g.:
SELECT a.id, a.title, a.year, a.avg_rate, a.total_times_rated,
(SELECT rating FROM ratings WHERE user_id = ? AND record_id = a.id) as user_rating
FROM (SELECT re.id as id, re.title as title, re.year as year, ROUND(avg(ra.rating)) as avg_rate,
COUNT(ra.record_id) as total_times_rated
FROM records re
LEFT JOIN ratings ra ON ra.record_id = re.id
GROUP BY re.id) a;
i have two table a,b and both tables structure is same as below
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| srno | int(11) | NO | PRI | NULL | auto_increment |
| domain | varchar(50) | NO | UNI | NULL | |
| timestamp | timestamp | YES | | NULL | |
| source | varchar(100) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
i want domain count from both table on particular date
so plz help
I think the tricky part of the question is that you need union all to bring the tables together. The rest of the question is unclear. If I interpret it as getting all domains with their counts on one particular day:
select domain, count(*)
from ((select a.* from a) union all
(select b.* from b)
) ab
where timestamp >= $YOURDATE and
timestamp < date_add($YOURDATE, interval 1 day)
group by domain;
Note: Having two tables with exactly the same structure is usually a sign of poor database design. A single entity is usually placed in a single table. More typically, there would be one table with a column specifying "a" or "b".
I'm slowly teaching myself MySQL methods, and I'm having a tough time with this. I haven't even been able to figure out HOW to Google the question.
I have the following two tables (I think my data is normalized, but suggestions welcome):
Table 1
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| rate_id | int(11) | NO | PRI | NULL | auto_increment |
| rate | decimal(9,2) | YES | | NULL | |
| guess | decimal(9,2) | YES | | NULL | |
| date | date | YES | MUL | NULL | |
| house_id | int(11) | NO | MUL | NULL | |
| date_mod | date | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
Table 2
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(64) | YES | | NULL | |
| beds | int(2) | YES | | NULL | |
| baths | int(2) | YES | | NULL | |
| pets | char(4) | YES | | NULL | |
| pool | char(4) | YES | | NULL | |
+-----------------+---------------+------+-----+---------+----------------+
I want to populate guess with the average rate of all properties during the same date period, based on similar properties in table 2. That is, for each id/house_id, I need all the houses that are similar (same beds, baths, view, etc.), and then the average of all the rates on the same dates.
My biggest issue is that I don't understand how to reference a field in a second table based on the id selected. This is what I'm starting with - just to see if I can get averages to return (I know this won't UPDATE the guess field).
SELECT AVG(t1.rate)
INNER JOIN t2 ON (t1.house_id = t2.id)
WHERE t2.beds = t2.beds
AND t2.baths = t2.baths
AND t2.pets = t2.pets
AND t1.date = t1.date
AND t1.house_id = 2;
Aside from the fact that the SQL command doesn't complete - I think it's obvious that my SQL knowledge is woefully inadequate - I think I'm just missing a more complex SQL method to identify the fields I'm looking for. Can anybody help?
#Strawberry - appreciate the comments. As it turns out, I already had AVG() working (I had already Googled it)
My problems were in two sets. First, how does one get column values from one table to use to get keys for us on another table. I didn't realize that you could use a nested SELECT statement to do this - although I still haven't convinced myself this is the most efficient way to do this.
Second, the average function was grouping all rates together into one average. I was able to do a bit of manipulation to produce the output I was looking for, but ultimately, the GROUP BY function was able to provide me most of the functionality I needed. Below is basically what I ended up with.
SELECT date, AVG(t1.rate) FROM rates
JOIN houses ON (t1.house_id = t2.id)
WHERE beds = (SELECT beds FROM t2 WHERE id = 2)
AND baths = (SELECT baths FROM t2 WHERE id = 2)
AND pets = (SELECT pets FROM t2 WHERE id = 2)
GROUP BY date;
Thanks for commenting.
I'm trying to run a query on a table that we keep for transactions regarding aspects of records of our database. To be more specific, when we "expire" an "asset" (as we call it), we change it's state to expired in the main table, and then record the record of when it was expired in another (this was not my design).
The problem is, sometimes the end user gets impatient with the front-end and we end up with multiple expired transactions for a specific record from the other table.
The table in question is as follows:
+---------------+-----------------------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------------------------+------+-----+-------------------+-------+
| m_id | int(11) | NO | PRI | 0 | |
| a_ordinal | int(11) | NO | PRI | 0 | |
| date_expired | datetime | NO | PRI | | |
| expire_state | enum('EXPIRED','UNEXPIRED') | YES | | NULL | |
| note | text | YES | | NULL | |
| created_by | varchar(40) | YES | | NULL | |
| creation_date | datetime | NO | | | |
| updated_by | varchar(40) | NO | | | |
| last_update | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------------+-----------------------------+------+-----+-------------------+-------+
From what I can ascertain, m_id, a_ordinal and date_expired form a composite key.
What I need is a query to the table to display the most recent transaction for each expired record (m_id, a_ordinal, expired_date). Currently it's displaying 809 records, but that's because we could have multiple instances of when the record was expired:
| 2223 | 20 | 2011-05-02 12:15:43 | EXPIRED | 165 Plays. Program quality is poor.
| 2223 | 20 | 2011-05-02 12:16:05 | EXPIRED | 165 Plays. Program quality is poor.
I know it involves a sub-query with a join, (or perhaps not?) but it's been 5 years since I've worked with MySQL, and I'm very rusty. Any help would be appreciated!!
SELECT t.m_id, t.a_ordinal, t.date_expired, t.note
FROM expiry_table_name t
INNER JOIN (
SELECT m_id, a_ordinal, MAX(date_expired) AS date_expired
FROM expiry_table_name
GROUP BY m_id, a_ordinal
) g
ON g.m_id = t.m_id
AND g.a_ordinal = t.a_ordinal
AND g.date_expired = t.date_expired
n.b. If you have duplicate date_expired values (for a specific m_id, a_ordinal combination) you'll need to do something more sophisticated.
I believe you'll need to join on a subquery to do this... try the following:
SELECT
yt.m_id,
yt.a_ordinal,
yt.date_expired
FROM
yourtable yt
INNER JOIN (
SELECT m_id, a_ordinal, MAX(date_expired) as `max_date`
FROM yourtable
GROUP BY m_id, a_ordinal) dt
ON (yt.m_id = dt.m_id AND yt.a_ordinal = dt.a_ordinal AND yt.date_expired = dt.max_date)