Query to add rows until multiple of 10 - sql

I need a query with a column with row number (probably using ROW_NUMBER() ) and if the result are 8 rows (e.g.) the query should result 10 rows with rows 9 and 10 blank except row number. If the result is 15 rows the result should be 20 rows, and so on...
It is possivel?

Normally, something like this would be done in the application layer. However, you can do this in SQL:
select t.*
from table t
union all
select nulls.*
from (select 1 as n union all select 2 union all . . . select 10
) n cross join
(select count(*) cnt from table) cnt left join
table nulls
on 1 = 0
where 10 * floor(cnt / 10) + n.n <= cnt;
The first subquery gets all your data. The second gets the additional rows with NULL values. It uses a left join with "false" condition to get all the columns.

Related

Top n distinct values of one column in Oracle

I'm using a query where a part of it gets the top 3 of a certain column.
It creates a distinct subquery of the column, limited by 3 number of rows, and then filters those rows to the main query to do the top 3.
WITH subquery AS (
SELECT col FROM (
SELECT DISTINCT col
FROM tbl
) WHERE ROWNUM <= 3
)
SELECT col
FROM tbl
WHERE tbl.col = subquery.col
So the original table is like this:
col
-----
a
a
a
b
b
b
c
d
d
e
f
f
f
f
And the query returns the top 3 of the column (not the top 3 rows which would only be a):
col
-----
a
a
a
b
b
b
c
I'm trying to learn if there is a more correct way of doing this as the real query is big and duplicating its size with a subquery that looks almost the same just to get the top 3 is hard to work with and understand/modify.
Is there a better way to do the top first 3 distinct values of one column in Oracle?
Yes, you can use dense_rank and avoid duplicated code:
select col
from (select col, dense_rank() over (order by col) rnk from tbl)
where rnk <= 3
demo

Fetching the next 3 or adjacent rows based upon a condition in postgreSQL

I have a database of more than 10,000 rows. eg:
id text
1 abc
2 ghj
3 cde
4 hif
5 klm
6 bbc
7 jkl
8 mno
9 dbo
10 ijk
I need to fetch the next three rows where the text matches a condition.
For eg: if I am doing a text like '%bc% query it should return me rows with ids 1,2,3,4,6,7,8,9 as row #1 and #6 is a match
Use below query to get the desired result. I am assuming you want to calculate next based on ID only and ID is always increment by 1, as you have mentioned in question.
If ID doesn't always increment by 1 , then first add a ROW Number and then replace id in t2 subquery and join condition with row number.
select t1.id, t1.id_text
from test t1
join
(
select id from test where id_text like '%bc%'
UNION
select id+1 from test where id_text like '%bc%'
UNION
select id+2 from test where id_text like '%bc%'
UNION
select id+3 from test where id_text like '%bc%'
) t2
on t1.id = t2.id;
SQL Fiddle Link
with -- Test data
t(i, x) as (values
(1,'abc'),(2,'ghj'),(3,'cde'),(4,'hif'),(5,'klm'),(6,'bbc'),(7,'jkl'),(8,'mno'),(9,'dbo'),(10,'ijk'))
select r.*
from
t as t0 cross join lateral (
select *
from t
where t.i >= t0.i
order by t.i
limit 4) as r
where t0.x like '%bc%'
order by r.i;
Lateral joins allows to use previous table in the next subquery.
You could use something like this:
SELECT next.*
FROM test, test next
WHERE test.text LIKE '%bc%'
AND (test.id + 1 = next.id OR test.id + 2 = next.id OR test.id + 3 = next.id)
I am not going to assume that the ids have no gaps. One method uses lag():
select t.*
from (select t.*,
lag(text) over (order by id) as prev_text,
lag(text, 2) over (order by id) as prev_text2,
lag(text, 3) over (order by id) as prev_text3
from t
) t
where text like '%bc%' or
prev_text like '%bc%' or
prev_text2 like '%bc%' or
prev_text3 like '%bc%';
You can also do this with one comparison, using other window functions:
select id, text
from (select t.*,
sum( (text like '%bc%')::int ) over (order by id rows between 3 preceding and current row) as cnt
from t
) t
where cnt > 0;
With an index on id, this might be the fastest approach to solving the problem.

Find missing values in a sequence (sql)

Table1
Empid number
----------------
100 1
100 2
100 4
100 5
100 6
101 1
I'm self learning SQL, and a task I've come across is finding the missing values in sequence up to 12 and out putting which empid is associated.
I've attempted an approach that takes the above table and starts like
SELECT a number +1 , Min("through), MIn(by number) - 1
The entire approach use the existing numbers to find the missing "next/previous number. I'm able to output which numbers are missing. However I do not know how to group it with the associated id.
I also feel like I've complicated the task, I'm looking for guidance from anyone who can help on the best / most efficient way of going about this
Assuming that all empids and numbers are in the table somewhere, you can do this with a cross join and filter. In MS Access, this looks like:
select e.empid, n.number
from (select distinct empid from t) as e,
(select distinct number from t) as n
where not exists (select 1
from t
where t.empid = e.empid and t.number = n.number
);
This will not quite work for the data you have supplied. To handle that situation, you need a table that has the 12 numbers you are looking for.
Assumes you create a numbers table having Number column with 12 records value 1 to 12.
SELECT N.*, E.*
FROM NUMBERS N
CROSS JOIN (SELECT Distinct EmpID FROM table1) E
LEFT JOIN table1 T
on T.EmpID = E.EmpID
and T.Number = N.Number
WHERE T.EmpID is null
or substitute a derrived table for numbers table above
something like
(Select 1 as Number UNION ALL
Select 2 as Number UNION ALL
Select 3 as Number UNION ALL
Select 4 as Number UNION ALL
Select 5 as Number UNION ALL
Select 6 as Number UNION ALL
Select 7 as Number UNION ALL
Select 8 as Number UNION ALL
Select 9 as Number UNION ALL
Select 10 as Number UNION ALL
Select 11 as Number UNION ALL
Select 112 as Number)
I cant remember if MS Access will let you do this though...

MySQL RAND() 7 LIMIT

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 ;

Select database rows in range

I want to select the rows between A and B from a table. The table has at least A rows but it might have less than B rows.
For example if A = 2, B = 5 and the table has 3 rows it should return rows 2 and 3.
How could I get the rows in such a range?
I am using Microsoft SQL Server 2008.
You can use something similar to what's being described in this SO question.
I.E.
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY YOUR_ORDERED_FIELD) as row FROM YOUR_TABLE
) a WHERE row > 5 and row <= 10
Where A = 5 and B = 10 in your example.
SELECT *,ROW_NUMBER() OVER
(ORDER BY ordercol) AS 'rank'
FROM table
where rank between #a and #b