First of all, I'm not familiar with SQL in depth, so this may be a beginner question.
I know how to select data ordered by Id: SELECT * FROM foo ORDER BY id LIMIT 100 as well as how to select a random subset: SELECT * FROM foo ORDER BY RAND() LIMIT 100.
I'd like to merge these two queries into 1 in a zip manner, choosing limit/2 from each (i.e. 50). For example:
0
85
1
35
2
38
3
19
4
...
I would like to avoid duplicates. The easiest way is probably to just add a WHERE id > 100/2 to the part of the query that retrieves randomly ordered rows.
Additional info: It is unknown how many rows exist.
To get the "zip-manner" merge add a generated rownumber to each query and use an union with order by rownnumber.
Use even numbers for one and odd numbers for the other query.
Try this for MySQL
SELECT
#rownum0:=#rownum0+2 rn,
f.*
FROM ( SELECT * FROM foo ORDER BY id ) f, (SELECT #rownum0:=0) r
UNION
SELECT #rownum1:=#rownum1+2 rn,
b.*
FROM ( SELECT * FROM bar ORDER BY RAND() ) b, (SELECT #rownum1:=-1) r
ORDER BY rn
LIMIT 100
This should be self-explicative but doesnt remove duplicates:
select #rownum:=#rownum+1 as rownum,
(#rownum-1) % 50 as sortc, u.id
from (
(select id from player order by id limit 50)
union all
(select id from player order by rand() limit 50)) u,
(select #rownum:=0) r
order by sortc,rownum;
If you replace "union all" with "union", you remove duplicates but get less rows as a consequence.
This will deal with duplicates, does not restrict random numbers in the ids > 50, and always return 100 rows:
SELECT #rownum := #rownum + 1 AS rownum,
( #rownum - 1 ) % 50 AS sortc,
u.id
FROM ((SELECT id
FROM foo
ORDER BY Rand()
LIMIT 50)
UNION
(SELECT id
FROM foo
WHERE id <= 100
ORDER BY id)) u,
(SELECT #rownum := 0) r
WHERE #rownum < 100
ORDER BY sortc,
rownum DESC
LIMIT 100;
SELECT * FROM foo ORDER BY id LIMIT 50 UNION SELECT * FROM foo ORDER BY RAND() LIMIT 50
If I understand your requirement correctly. UNION removes duplicates by itself
Related
Given a table of IDs in an Oracle database, what is the best method to randomly flag (x) percent of them? In the example below, I am randomly flagging 20% of all records.
ID ELIG
1 0
2 0
3 0
4 1
5 0
My current approach shown below works fine, but I am wondering if there is a more efficient way to do this?
WITH DAT
AS ( SELECT LEVEL AS "ID"
FROM DUAL
CONNECT BY LEVEL <= 5),
TICKETS
AS (SELECT "ID", 1 AS "ELIG"
FROM ( SELECT *
FROM DAT
ORDER BY DBMS_RANDOM.VALUE ())
WHERE ROWNUM <= (SELECT ROUND (COUNT (*) / 5, 0) FROM DAT)),
RAFFLE
AS (SELECT "ID", 0 AS "ELIG"
FROM DAT
WHERE "ID" NOT IN (SELECT "ID"
FROM TICKETS)
UNION
SELECT * FROM TICKETS)
SELECT *
FROM RAFFLE;
You could use a ROW_NUMBER approach here:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY dbms_random.value) rn,
COUNT(*) OVER () cnt
FROM yourTable t
)
SELECT t.*,
CASE WHEN rn / cnt <= 0.2 THEN 'FLAG' END AS flag -- 0.2 to flag 20%
FROM cte t
ORDER BY ID;
Demo
Sample output for one run of the above query:
Note that one of five records is flagged, which is 20%.
I need to sort a particular query's result in a way that top 2 records are selected on a particular order and rest in some other particular order.
Basically something like this
WITH MY_TABLE AS
(
SELECT NEARBY_CITY_ID, CNT_USERS, DISTANCE_CITY
FROM MY_RELATED_CITIES
WHERE CITY_ID = :MYCITYID
)
SELECT *
FROM MY_TABLE
ORDER BY DISTANCE
LIMIT 2
UNION
SELECT *
FROM MY_TABLE
ORDER BY CNT_USERS, DISTANCE
LIMIT 48;
But this query is not syntactically right.
Can I somehow store the Result of query used to make MY_TABLE in some Json or Array or Cursor Object and then use that as a Table later in code to achieve this?
Did you try using parentheses?.
WITH my_table AS
(
SELECT nearby_city_id,
cnt_users,
distance_city
FROM my_related_cities
WHERE city_id = :MYCITYID )
SELECT *
FROM (
SELECT *
FROM my_table
ORDER BY distance limit 2 ) A
UNION
(
SELECT *
FROM my_table
ORDER BY cnt_users,
distance limit 48 ) B;
My database table has 15 records and I want to show 9 at random on screen.
SELECT * FROM tablename ORDER BY RAND() LIMIT 9
This works as expected, but what if the table only has 9 records? I need to pull 15 random records.
I understand this will duplicate one or more records, but that's my intention.
Your select will only pull the number of records in the table regardless of the order by. You can use various means to duplicate the table data, however, before you order them. For example, union all of the rows together twice:
select * from
(
select * from tablename
union all
select * from tablename
) as tmp
order by rand() limit 9
RAND() itself is not efficient when you deal with a large database.
A better way of doing such query is to:
-1. Query the largest id (assume id is the unique key)
-2. use javascript of php function to generate 15 random numbers from 1 to max_id, push to -array
-3. Implode the array (e.g. $id_list = "'".implode("', '", $id_list)."'")
-4. Select * from tablename where id in ($id_list)
This will work even if you have only 1 row in the table. If you have less than 15 (say 11) rows, you'll have all 11 in the result plus 4 more random ones:
SELECT col1, col2, ..., colN -- the columns of `tablename` only
FROM
( SELECT a.i, b.j, t.*
FROM
( SELECT *, RAND() AS rnd
FROM tablename
ORDER BY rnd LIMIT 15
) AS t
CROSS JOIN
( SELECT 1 AS i UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4 )
AS a
CROSS JOIN
( SELECT 1 AS j UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4 )
AS b
ORDER BY i, j, rnd
LIMIT 15
) AS t15
ORDER BY RAND() ;
If you want "more" randomness, having duplicate or triplicate rows in the results with possibly some rows not shown at all, replace the last five lines with:
AS b
ORDER BY RAND()
LIMIT 15
) AS t15 ;
How to select top 2 , bottom 2 and 6 random (not in Top 2 and Bottom 2) records of the table using one SQL select query?
In MS SQL 2005/2008:
with cte
as
(
select
row_number() over (order by name) RowNumber,
row_number() over (order by newid()) RandomOrder,
count(*) over() Total,
*
from sys.tables
)
select *
from cte
where RowNumber <= 2 or Total - RowNumber + 1 <= 2
union all
select *
from
(
select top 6 *
from cte
where RowNumber > 2 and Total - RowNumber > 2
order by RandomOrder
) tt
Replace sys.tables with your table name and alter order by name to specify order condition for top 2 and bottom 2.
Perhaps not a single select statment, but it can be executed in one call:
/* Top 2 - change order by to get the 'proper' top 2 */
SELECT * from table ORDER BY id DESC LIMIT 2
UNION ALL
/* Random 6.. You may want to add a WHERE and random data to get the random 6 */
/* Old Statement before edit - SELECT * from table LIMIT 6 */
SELECT * from table t
LEFT JOIN (SELECT * from table ORDER BY id DESC LIMIT 2) AS top ON top.id = t.id
LEFT JOIN (SELECT * from table ORDER BY id DESC LIMIT 2) AS bottom ON bottom.id = t.id
WHERE ISNULL(top.id ) AND ISNULL(bottom.id)
ORDER BY RANDOM()
LIMIT 6
UNION ALL
/* Bottom 2 - change order by to get the 'proper' bottom 2 */
SELECT * from table ORDER BY id ASC LIMIT 2
Something along those lines. Basically the UNION All is the trick.
Assuming the "order" is by the id column:
select * from (select id, id from my_table order by id limit 2) t1
union
select * from (select id, id from my_table where id not in (
select * from (select id from my_table order by id asc limit 2) t22
union
select * from (select id from my_table order by id desc limit 2 ) t23)
order by rand()
limit 6) t2
union
select * from (select id, id from my_table order by id desc limit 2) t3
EDIT: Fixed syntax and tested query - it works
I have an adress table and I need to take the near number. For example if I´m entenring the number 256 in this case I´ll take 257 because:
254<--256->257
Somebody knows the solution.
Thanks and sorry for my bad English.
The distance between 257 and the number is abs(number-257). So you can find (one of) the nearest numbers with:
select number
from (
select number
from yourtable
order by abs(number-257)
) sub
where rownum < 2
SELECT *
FROM mytable
WHERE mynumber BETWEEEN 256 - 2 AND 256 + 2
If you just need to pick the first match, use this:
SELECT *
FROM (
SELECT *
FROM (
SELECT *
FROM (
SELECT *
FROM mytable
WHERE mynumber <= 256
ORDER BY
mynumber DESC
)
WHERE rownum = 1
UNION ALL
SELECT *
FROM (
SELECT *
FROM mytable
WHERE mynumber > 256
ORDER BY
mynumber
)
WHERE rownum = 1
)
ORDER BY
ABS(256 - number), mynumber DESC
)
WHERE rownum = 1
This is more index efficient, since the final ORDER BY will sort at most two records.
I tried the sql in other way but based on the Quassnoi´s SQL. I´ve made some revisions and it´s working well. Look:
(SELECT * FROM
(SELECT number
FROM numberList
WHERE number < ?
ORDER BY number DESC)
WHERE ROWNUM=1)
UNION ALL
(SELECT * FROM
(SELECT number
FROM numberList
WHERE numeber > ?
ORDER BY number ASC)
WHERE ROWNUM=1)
Try this
Num integer := 236;
select Max(number) AS NearestAndGreatest from mytbl t
join(
select MIN(T.distance) AS dist from(
select number,abs(number-Num) AS distance from mytbl)T)X
on abs(number-Num) = X.dist