MySQL - select rows with limit - mysql
How can I select a certain number of rows, based on a condition (using IN or any other conditional), and if the number of rows returned by the condition is less than LIMIT x then to select from the remainig rows until the LIMIT x is met?
So, if I have the following table:
id comment ord
1 ... null
2 ... 1
3 ... 2
4 ... null
then the result set should be, using LIMIT 3:
id comment ord
2 ... 1
3 ... 2
1 ... null
If the ord column is not null, then I want to select the respective row(s), if not, I want to select one or more from the rest of the rows, having ord NULL, until the LIMIT 3 condition is reached.
Another example, if I have the next table data:
id comment ord
1 ... 3
2 ... 1
3 ... 2
4 ... null
Then the result set should be
id comment ord
2 ... 1
3 ... 2
1 ... 3
I have tried this mysql code:
SELECT t.* FROM table t
WHERE
t.ord IN (SELECT t1.ord FROM table t1 WHERE t1.ord IS NOT NULL ORDER BY t1.ord ASC)
OR
t.id IN (SELECT t2.id FROM table t2 WHERE t2.ord IS NULL ORDER BY t2.id ASC)
LIMIT 3;
But I always get the rows that have ord NULL, even if I have some ord columns not null.
Any help please?
Put the check for whether ord is null in your ORDER BY:
SELECT *
FROM table
ORDER BY ord IS NULL, ord, id
LIMIT 3
ord IS NULL will be 0 for non-null ord, 1 for null ord, so this will put all the non-null rows first. Within those it will order by ord, then the remainder will be ordered by id.
Then LIMIT 3 will select the first 3 of all of these.
Related
How i can get all query in one field?
I've two tables like this: First : id num 1 a 2 b 3 c Second: id first_id value 11 1 a1 12 1 a2 13 1 a3 And I need to get result like this: id value 1 a1-a2-a3 I've tried with query: SELECT first.id, (SELECT second.value FROM second WHERE second.first_id = first.id) AS value FROM first But I've got #1242 error. How I can do it?
You can use group_concat() select first_id as id, group_concat(`value` order by `value` separator '-') as combined_values FROM second_table group by first_id
How to find duplicate and update column value of all but the most recent entry
I have a table items with columns item_id, lockup_id, date, archive. I need to be able to go through the lookup_id column and identify duplicates, changing the archive value to 1 on every duplicate EXCEPT the newest entry in the table. item_id Lookup_id date archive ------------------------------------------------ 1234 4 1-1-19 0 1235 4 1-1-19 0 1236 4 1-1-19 0 1237 2 1-1-19 0 1238 1 1-1-19 0 1239 1 1-1-19 0 I've so far managed to find the duplicates using the following statement, but I'm at a bit of a loss where to go with this to achieve my desired result. 'SELECT `item_id` , `lookup_id`, `date`, `archive` FROM items WHERE `item_id` IN ( `SELECT `item_id` FROM items GROUP BY `item_id` HAVING COUNT( `item_id` ) >1 ) ORDER BY `item_id`;
You can do it in two steps. First set all values in archive to 1: update items set archive = 1 where 1; Then set archive = 0 for "newest" entries only: update items i inner join ( select max(item_id) as item_id from items group by Lookup_id ) x using(item_id) set i.archive = 0; You will get the following result: item_id Lookup_id date archive 1234 4 1-1-19 1 1235 4 1-1-19 1 1236 4 1-1-19 0 1237 2 1-1-19 0 1238 1 1-1-19 1 1239 1 1-1-19 0 This method should be quite efficient with an index on (Lookup_id, item_id). Demo
Looks like item_id is sequential, assuming newest entry has the highest item_id you could filter for the highest item_id for each lookup_id and then update all records except these. update items set archive = 1 where item_id not in ( select max(item_id) from items group by lookup_id );
In order to archive all the items with the same lookup_id except the newer one you can use this sql statement UPDATE tn SET tn.archive = 1 FROM table_name tn WHERE (SELECT COUNT(tn2.id) FROM table_name AS tn2 WHERE tn2.lookup_id = tn.lookup_id) > 1 AND tn.id NOT IN (SELECT tn2.id FROM table_name AS tn2 WHERE tn2.lookup_id = tn.lookup_id ORDER BY tn.date DESC, tn.id DESC LIMIT 1); In the where conditions first we check if more than one item with the same lookup_id exists and then we check that the actual item is not the newer of all the items with the same lookup_id.
Looking at you example I am assuming the latest entry is the one with highest item id if that's the case you can create a CTE with a column and use row number / partition by Something like this - the join will change depending on which columns are unique ;WITH cte_test AS (SELECT item_id , lookup_id , ROW_NUMBER() OVER (PARTITION BY lookup_id ORDER BY item_id ) AS rn FROM items ) UPDATE it2 SET it2.archive = 1 FROM items it2 INNER JOIN cte_test ct ON ct.item_id = it2.item_id AND ct.lookup_id = it2.lookup_id where rn > 1
Mysql only get newest record where columns are set and get the empty columns from the next row
I have a MySQL database table with many columns that can be empty (null). I would like in one result row the newest value for every column for one machine. So, if null, the value will be of one older row, like illustrated below. Table content: id name motorSpeed motorDelay F1type F2type F3type 1 001 200 null 1 null null 2 002 400 0 0 0 0 3 001 null 50 0 1 1 Desired result: id name motorSpeed motorDelay F1type F2type F3type 3 001 200 50 0 1 1 What would be the best query to get this aggregated result?
I suspect name is the key and it can not be null. Also that you want to get the 'latest' values for name=001. SELECT a.id, b.name, c.motorSpeed, d.motorDelay, e.F1type, f.F2type, g.F3type FROM (SELECT * FROM table WHERE id IS NOT NULL ORDER BY id DESC LIMIT 1) a LEFT JOIN (SELECT * FROM table WHERE name IS NOT NULL ORDER BY id DESC LIMIT 1) b ON b.name=a.name LEFT JOIN (SELECT * FROM table WHERE motorSpeed IS NOT NULL ORDER BY id DESC LIMIT 1) c ON c.name=a.name LEFT JOIN (SELECT * FROM table WHERE motorDelay IS NOT NULL ORDER BY id DESC LIMIT 1) d ON d.name=a.name LEFT JOIN (SELECT * FROM table WHERE F1type IS NOT NULL ORDER BY id DESC LIMIT 1) e ON e.name=a.name LEFT JOIN (SELECT * FROM table WHERE F2type IS NOT NULL ORDER BY id DESC LIMIT 1) f ON f.name=a.name LEFT JOIN (SELECT * FROM table WHERE F3type IS NOT NULL ORDER BY id DESC LIMIT 1) g ON g.name=a.name WHERE a.name='001';
SELECT ID, NAME, CASE WHEN MOTORSPEED IS NULL THEN MIN(MOTORSPEED) ELSE MOTORSPEED END AS MOTORSPEED, CASE WHEN MOTORDELAY IS NULL THEN MAX(MOTORDELAY) ELSE MOTORDELAY END AS MOTORDELAY, CASE WHEN F1TYPE IS NULL THEN MAX(F1TYPE) ELSE F1TYPE END AS F1TYPE, CASE WHEN F2TYPE IS NULL THEN MAX(F2TYPE) ELSE F2TYPE END AS F2TYPE, CASE WHEN F3TYPE IS NULL THEN MAX(F3TYPE) ELSE F3TYPE END AS F3TYPE FROM YOURTABLE;
MySQL- Select at least n rows per group
Suppose you have id / value 1 2 1 3 1 6 2 3 3 1 3 3 3 6 And I want to retrieve at least n rows per id group, let's say n = 4. In addition, it would help if a counter is added as a column. So the results should be like: counter / id / value 1 1 2 2 1 3 3 1 6 4 null null 1 2 3 2 null null 3 null null 4 null null 1 3 1 2 3 3 3 3 6 4 null null regards
I'm assuming that the combination of id and value is unique. Here's how you can do it without using MySQL variables: SELECT a.n AS counter, b.id, b.value FROM ( SELECT aa.n, bb.id FROM ( SELECT 1 AS n UNION ALL SELECT 2 AS n UNION ALL SELECT 3 AS n UNION ALL SELECT 4 AS n ) aa CROSS JOIN ( SELECT DISTINCT id FROM tbl ) bb ) a LEFT JOIN ( SELECT aa.id, aa.value, COUNT(*) AS rank FROM tbl aa LEFT JOIN tbl bb ON aa.id = bb.id AND aa.value >= bb.value GROUP BY aa.id, aa.value ) b ON a.id = b.id AND a.n = b.rank ORDER BY a.id, a.n
The next blog post describes the solution to your query: SQL: selecting top N records per group. It requires an additional small table of numbers, which is utilized to "iterate" the top N values per group via String Walking technique. It uses GROUP_CONCAT as a way to overcome the fact MySQL does not support Window Functions. This also means it's not a pretty sight! An advantage of this technique is that it does not require subqueries, and can optimally utilize an index on the table. To complete the answer to your question, we must add an additional columns: you have requested a counter per item per group. Here's an example using the world sample database, choosing top 5 largest counties per continent: CREATE TABLE `tinyint_asc` ( `value` tinyint(3) unsigned NOT NULL default '0', PRIMARY KEY (value) ) ; INSERT INTO `tinyint_asc` VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),(40),(41),(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56),(57),(58),(59),(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71),(72),(73),(74),(75),(76),(77),(78),(79),(80),(81),(82),(83),(84),(85),(86),(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),(127),(128),(129),(130),(131),(132),(133),(134),(135),(136),(137),(138),(139),(140),(141),(142),(143),(144),(145),(146),(147),(148),(149),(150),(151),(152),(153),(154),(155),(156),(157),(158),(159),(160),(161),(162),(163),(164),(165),(166),(167),(168),(169),(170),(171),(172),(173),(174),(175),(176),(177),(178),(179),(180),(181),(182),(183),(184),(185),(186),(187),(188),(189),(190),(191),(192),(193),(194),(195),(196),(197),(198),(199),(200),(201),(202),(203),(204),(205),(206),(207),(208),(209),(210),(211),(212),(213),(214),(215),(216),(217),(218),(219),(220),(221),(222),(223),(224),(225),(226),(227),(228),(229),(230),(231),(232),(233),(234),(235),(236),(237),(238),(239),(240),(241),(242),(243),(244),(245),(246),(247),(248),(249),(250),(251),(252),(253),(254),(255); SELECT Continent, SUBSTRING_INDEX( SUBSTRING_INDEX( GROUP_CONCAT(Name ORDER BY SurfaceArea DESC), ',', value), ',', -1) AS Name, CAST( SUBSTRING_INDEX( SUBSTRING_INDEX( GROUP_CONCAT(SurfaceArea ORDER BY SurfaceArea DESC), ',', value), ',', -1) AS DECIMAL(20,2) ) AS SurfaceArea, CAST( SUBSTRING_INDEX( SUBSTRING_INDEX( GROUP_CONCAT(Population ORDER BY SurfaceArea DESC), ',', value), ',', -1) AS UNSIGNED ) AS Population, tinyint_asc.value AS counter FROM Country, tinyint_asc WHERE tinyint_asc.value >= 1 AND tinyint_asc.value <= 5 GROUP BY Continent, value ;
Complex SQL Querying: Two queries within the same table?
I have a table like: ID | LABEL | SOME_VALUE 1 a rand_1 2 a NULL 3 b rand_9 4 c rand_3 5 c rand_3 6 c rand_3 7 d NULL 8 d rand_4 As you can see, ID is unique, label is not unique (can be 1 or more) and some_value is also not unique. What I want to do is the following: I want to get a unique list of LABELS, which exist in the database in more than one rows (min 2) and of which rows has SOME_VALUE not NULL. So I would get: ID | LABEL | SOME_VALUE 1 a rand_1 2 a NULL 7 d NULL 8 d rand_4 in return. How can I achieve this?
There are two versions. First one does exactly as listed in results, eliminating rand_3 because even though it appears three times all the values are the same (I don't see distinct condition specified in question). There must be a better way, but as they say I can't brain today, I have the dumb :-) select * from tbl inner join ( select label FROM tbl GROUP BY Label HAVING count (distinct some_value) + sum(distinct case when some_value is null then 1 else 0 end) > 1 ) a on tbl.label = a.label Second one retrieves C also following the requirements (some_value being not null for at least one of some_value). select * from tbl inner join ( select label FROM tbl GROUP BY Label HAVING count(*) > 1 and count(some_value) > 0 ) a on tbl.label = a.label And there is Sql Fiddle.
The HAVING parameter limits grouped items: SELECT Label FROM dbo.TableName WHERE NOT Some_Value IS NULL GROUP BY Label HAVING COUNT(*) > 2
SELECT t1.* FROM yourTable t1 JOIN yourTable t2 ON t1.LABEL = t2.LABEL AND t1.ID < t2.ID WHERE t1.SOME_VALUE IS NOT NULL OR t2.SOME_VALUE IS NOT NULL
This should work - SELECT test.* FROM ( SELECT label FROM test GROUP BY Label HAVING COUNT(DISTINCT IFNULL(some_value, '~null~')) > 1 ) AS tmp INNER JOIN test ON tmp.label = test.label;