I have a query like that:
SELECT id, title
FROM tbl_item
WHERE id!=477
AND (projectid=172 OR styleid=66)
ORDER BY timestamp DESC LIMIT 4;
How can I order the item by same projectid first (list all projectid 172), then same styleid (66) even if the timestamp of styleid is greater.
id projectid styleid timestamp
475 172 66 1401660000
459 172 66 1398981600
458 167 66 1398636000
456 172 64 1397685600
449 63 66 1394665200
444 167 66 1391727600
411 113 66 1386630000
408 62 66 1385938800
407 159 66 1385938800
387 159 66 1375826400
With my snapshot above, my desire result is merge of two queries:
Query 1: SELECT id FROM tbl_item WHERE projectid=172;
Query 2: SELECT id FROM tbl_item WHERE styleid=66;
Desire result ids: 475,459,456,458
The first 3 ids (475,459,456) is result of #1, and the 458 is result of #2 (LIMIT 4 results)
Thank you!
You can add multiple columns to the ORDER BY, they are prioritised from left to right see docs:
SELECT id, projectid, styleid, timestamp
FROM tbl_item
WHERE ...
ORDER BY projectid, styleid, timestamp DESC;
N.B. You do not need to SELECT the columns used by the ORDER BY, I have just included them for clarity.
UPDATE
From your update to the question, it can be done bespokely like this
SELECT id, projectid, styleid, timestamp
FROM tbl_item
WHERE projectid=172
OR styleid=66
ORDER BY projectid=172 DESC,
projectid != 172 AND styleid=66 DESC,
timestamp DESC
LIMIT 4;
Related
I have a database with some fields and I want to apply a unique value constraint to a table:
ALTER TABLE assessment_submissions
ADD CONSTRAINT UC_Question UNIQUE (evaluated_user, evaluator_user, question_id);
But there is some data inside the table that doesn't allow me to put this constraint.
I got an error when I tried to apply the constraint:
SQL error 1062: Duplicate entry 154-154-45 for key UC_Question
Take a look at the image below:
The results on the line that starts with id 131271 and id 131413 have the same values on the fields evaluated_user, evaluator_user, and question_id.
This way it's not possible to apply the constraint.
I deleted the duplicated row, but I still was not able to apply the constraint.
I suppose there are more duplicate data inside that table. How can I find all data that is duplicated inside that table? Which query can I use to do that?
I have no idea where I can start.
Kindly use any of these two based on the need at hand. Essentially, you need to decide whether to retain the duplicate set that first hit the database or the set that arrived last.
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id < t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
DELETE t1 FROM assessment_submissions t1 INNER JOIN assessment_submissions t2
WHERE t1.id > t2.id
AND t1.evaluated_user=t2.evaluated_user AND t1.evaluator_user = t2.evaluator_user
AND t1.question_id=t2.question_id;
I prefer the above approach for user environments that have MySQL versions earlier than 8.X
It depends a bit on whether you want to examine the rows before deciding which ones to delete or not (see 1. respectively 2. below).
Let's say you have the following example data:
id evaluated_user evaluator_user question_id answer_id
1 262 275 157 573
2 262 275 162 593
3 262 275 332 1260
4 262 275 161 589
5 262 275 157 573
6 262 275 157 1425
7 262 275 167 726
8 262 275 167 4593
If you want to take a look at the rows to get the information which ones you need to delete, just grouping by wont get you the ids.
If you have MySQL 8.0, you can use a window function to calculate the number of duplicates for each unique (evaluated_user, evaluator_user, question_id) combination as follows (ordering is optional):
select *, count(*) over (partition by evaluated_user, evaluator_user, question_id) as cnt
from example e
order by cnt desc, evaluated_user, evaluator_user, question_id
This will give you
id evaluated_user evaluator_user question_id answer_id cnt
1 262 275 157 573 3
5 262 275 157 573 3
6 262 275 157 1425 3
7 262 275 167 726 2
8 262 275 167 4593 2
4 262 275 161 589 1
2 262 275 162 593 1
3 262 275 332 1260 1
In this table, all entries with cnt > 1 are the rows you are interested in. If you just want them, wrap this into a select * from ... where cnt > 1.
For previous versions of MySQL (which don't support window functions), you can achieve the same using a query like the one from #DNNX's answer and joining the result with the original table:
select e.*
from example e
join (select evaluated_user, evaluator_user, question_id
from example
group by evaluated_user, evaluator_user, question_id
having count(*) > 1) f
on e.evaluated_user = f.evaluated_user and
e.evaluator_user = f.evaluator_user and
e.question_id = f.question_id
Either of this will give you the rows you may want to examine to decide which ones to delete:
id evaluated_user evaluator_user question_id answer_id
1 262 275 157 573
5 262 275 157 573
6 262 275 157 1425
7 262 275 167 726
8 262 275 167 4593
In case you don't need to inspect the data first to decide which records you delete, as long as one line remains, you can build your DELETE statement elegantly using the RANK() function (again, MySQL 8.0):
with subtab as (select id, rank() over (partition by evaluated_user, evaluator_user, question_id order by id) as rnk
from example)
delete from example e
where e.id in (select id
from subtab
where rnk > 1)
This example will bulk delete all duplicate rows except the one with the smallest id for each unique combination. You can modify the order by statement to influence which records to delete. For example, to keep the record with the highest id instead, you can order by id desc. Or if you wanted to keep the one with the smallest answer_id, you order by answer_id. Note: if you have duplicate entries in the column you are ordering by, you may end up with more than one row left. To avoid that, use row_number() instead of rank().
To get the same without window functions, you can use
delete e from example e
join example f
on e.evaluated_user = f.evaluated_user
and e.evaluator_user = f.evaluator_user
and e.question_id = f.question_id
and e.id > f.id ;
Again, the statement can be modified depending on which row you want to keep. For example, to keep the one with the highest answer_id, you change the last condition to and e.answer_id < f.answer_id.
See this db<>fiddle for all of the above in action.
This query will return all duplicate rows, along with a couple of IDs belonging to the same "group".
select evaluated_user, evaluator_user, question_id, count(*), min(id), max(id)
from assessment_submissions
group by evaluated_user, evaluator_user, question_id
having count(*) > 1
I have the following demo table
cid uid unixdate
110 90 129
109 85 128
108 81 127
107 90 126
106 85 125
105 70 124
I want to create an sql select to get only 1 row for each uid which would look like this
cid uid unixdate
110 90 129
109 85 128
108 81 127
105 70 124
But the result should be the LATEST entries (sort with unixdate DESC)
Have tried all from this example which looks very similar like for example.these queries
SELECT * FROM demo GROUP BY uid ORDER BY unixdate DESC
SELECT * From demo GROUP BY uid HAVING COUNT(*) >=1 order by unixdate DESC
but they don't get the latest but the first entry for each UID (instead of the latest)
NOTE running mysql Server version: 5.7.21-0ubuntu0.16.04.1 - (Ubuntu) and doing the sql queries using phpmyadmin interface
Try like this:
SELECT * FROM demo GROUP BY uid ORDER BY unixdate DESC;
where demo is the name of the table.
SQL Fiddle: http://sqlfiddle.com/#!9/2eb3d0/1
The problem is the group by will always return the first record in the group on the result set. This is the solution that worked.
SELECT * FROM demo WHERE unixdate IN
( SELECT MAX(unixdate) FROM demo GROUP BY uid )
ORDER BY unixdate
I have to get the last 50 records from my MySQL database.
Here is the structure of my test database:
ID S1 S2 S3 Date-time Label
13 32 55 33 2017-09-05 13:15:06 temperature
16 111 222 66 2017-09-05 19:22:14 temperature
17 44 55 33 2017-09-05 19:22:14 temperature
18 55 11 88 2017-09-12 14:22:00 temperature
21 77 1 200 2017-09-15 12:24:06 temperature
22 22 55 11 2017-09-19 14:37:00 temperature
How could I show only the last 3 data? for example:
18 55 11 88 2017-09-12 14:22:00 temperature
21 77 1 200 2017-09-15 12:24:06 temperature
22 22 55 11 2017-09-19 14:37:00 temperature
Greetings and thank you.
In Oracle12c you can use the fetch keywork:
SELECT *
FROM table
ORDER BY id DESC
FETCH FIRST 50 ROWS ONLY;
FOR ORACLE:
SELECT * FROM (
SELECT ID,
S1,
S2,
S3,
Date-time,
Label
FROM TABLE
ORDER BY ID DESC)
WHERE ROWNUM <= 50;
FOR MYSQL:
SELECT ID,
S1,
S2,
S3,
Date-time,
Label
FROM TABLE
ORDER BY ID DESC
LIMIT 50;
Here is a quick doc:
https://www.w3schools.com/sql/sql_top.asp
Edit:
For the last 50 rows:
SELECT * FROM (
SELECT * FROM table ORDER BY id DESC LIMIT 50
) sub
ORDER BY id ASC
Use Top N Query (row num<=50) fro first, for last 50 you can use "order by id desc"
First I was confused with the Post between ORACLE and MYSQL I apologize.
The solution at the end was the following:
SELECT * FROM inv ORDER BY id DESC LIMIT 50
then transform the ARRAY that I collect with the function:
var dorde = d0.reverse ();
thanks for everything.
I need to extract the required fields from a table along with relevant time stamp
SELECT * FROM Glm_Test.LicenseUsage where FeatureId='2';
Output :
VendorId,FeatureId,Total_Lic_Installed,Total_Lic_Used,Reserved,CurrentTime
1 2 106 19 67 2015-12-15 15:00:05
1 2 106 19 67 2015-12-15 15:02:02
1 2 106 19 69 2015-12-15 15:04:02
1 2 106 19 67 2015-12-15 15:06:01
1 2 106 20 67 2015-12-15 15:08:02
select VendorId,FeatureId,Total_Lic_Installed,Max(Total_Lic_Used),Reserved,CurrentTime from Glm_Test.LicenseUsage where FeatureId= '2' group by VendorId,FeatureId;
output:
1 2 106 20 69 2015-12-15 15:00:05
In the above 2 queries
1st query lists all entries from the table
and i want second query to return time stamp for the MAX value of column Total_Lic_Used but somehow it is returning me only timestamp of the first entry.
Help is much appreciated.
Selecting the columns which are not part of an aggregation function like count/max/min/sum... or not in group by clause will give unexpected results:
Other RBBMS wont allow these statements(gives error like):
sql server ==> the select list because it is not contained in either
an aggregate function or the GROUP BY clause
Oracle ==>not a GROUP BY expression
You can do this by a sub query and join
select
a.VendorId,
a.FeatureId,
a.Total_Lic_Installed,
b.max_Total_Lic_Used,
a.Reserved,
a.CurrentTime
from Glm_Test.LicenseUsage a
join (
select
VendorId,
FeatureId,
Max(Total_Lic_Used) max_Total_Lic_Used
from Glm_Test.LicenseUsage
where FeatureId = '2'
group by VendorId, FeatureId
) b
on a.VendorId = b.VendorId and
a.FeatureId = b.FeatureId and
a.Total_Lic_Used = b.max_Total_Lic_Used
sql fiddle demo
You can try this also;
select
`VendorId`,
`FeatureId`,
`Total_Lic_Installed`,
`Total_Lic_Used`,
`Reserved`,
`CurrentTime`
from Glm_Test.LicenseUsage
order by Total_Lic_Used desc
limit 1
demo
I have a exam results table which contains examid, level and the point got by the user. As you can see in the table
id examid level points
228 2 1 90
229 3 1 85
230 3 1 65 *
227 1 1 60 *
231 2 2 20
232 1 1 80
For each unique exam the highest points will be selected.
I want to select the rows with highest points for each unique exam and unique level. The row 232 has greater point than the row 227 and 232 will be in my resultset. Another one is the row 229 which has greater point than 230.
After selecting my resultset should be like the following:
id examid level points
228 2 1 90
229 3 1 85
231 2 2 20
232 1 1 80
I tried to query like
SELECT * FROM results WHERE userid = 20 GROUP BY examid ORDER BY points
which results only
id examid level points
227 1 1 60
229 3 1 85
228 2 1 90
SELECT examid, level, MAX(`points`)
FROM score
GROUP BY examid, level
ORDER BY id
See SQLFiddle here
If you want all fields (including id), you can JOIN the table back in.
SELECT results.*
FROM results
JOIN (
SELECT examid, level, max(points) AS points
FROM results
GROUP BY examid, level ) maxPoints
ON results.examid = maxPoints.examid
AND results.level = maxPoints.level
AND results.points = maxPoints.points
If you don't need the id, you can use a simple GROUP BY.
SELECT examid, level, MAX(points) AS points
FROM tablename
GROUP BY examid, level