Is there any way to take a table and select 10 records from a start point but if the end of table is reached, go back to the start? So a table of 100 records, selecting 10 starting at record 95 would being 95-100 and 1-4.
Assuming that you have a column with the record number, then you can use arithmetic to define the ordering:
select t.*
from table t
order by (recnum + (100 - 95)) % 100) ;
If not:
select t.*
from table t cross join (select count(*) as cnt from t) x
order by (recnum + (x.cnt - 95)) % x.cnt) ;
If your records are not sequentially numbered, then you can add the number:
select t.*
from (select t.*, count(*) over () as cnt,
row_number() over (order by recnum) as seqnum
from table t
) t
order by (seqnum + (cnt - 95)) % cnt) ;
Related
I have the following rows in the table:
dates
------------
"2021-01-02"
"2021-01-03"
"2021-01-11"
"2021-01-14"
...
I know that these rows present date ranges.
So, the first row is a range start, next row is a range end. Next row is a range start again and etc (the numbers of rows mod 2 = 0).
Is there a way to select such table as:
range_start | range_end
-------------+-------------
"2021-01-02" "2021-01-03"
"2021-01-11" "2021-01-14"
... ...
?
PostgreSQL version is 10.17
Use conditional aggregation with row_number():
select min(date), max(date)
from (select t.*, row_number() over (order by date) as seqnum
from t
) t
group by ceiling(seqnum / 2.0)
This should work:
WITH ordered_table AS (
SELECT
dates,
ROW_NUMBER () OVER (ORDER BY dates) AS creation_order
FROM your_table
)
SELECT
t1.dates AS range_start,
t2.dates AS range_end
FROM
ordered_table t1
INNER JOIN ordered_table t2 ON t2.creation_order = t1.creation_order + 1
WHERE (t1.creation_order % 2) = 1 -- counting from 1
For more details:
WITH in PG
row_number in PG
I have tried the following approaches which none of them worked:
Using SELECT TOP 50 PERCENT: BigQuery does not have top function
Using LIMIT (SELECT COUNT(*) FROM tabl)/2: the reason is BigQuery does not accept any non integer value.
Using SET to set the median value and then use WHERE
In BigQuery I would use window function percent_rank().
select t.* except (prnk)
from (select t.*, percent_rank() over(order by id) prnk from mytable t) t
where prnk <= 0.5
Note: any answer to your question will require that you provide a column to order your data. I assumed that this column is called id.
One method uses window functions:
select t.* except (seqnum, cnt)
from (select t.*, row_number() over (order by ?) as seqnum,
count(*) over () as cnt
from t
) t
where seqnum <= cnt / 2;
Another possibility would be to limit the data with a WHERE clause instead of LIMIT. This is an example if you want yo filter by an ID:
SELECT * FROM table_name as t
WHERE t.id <= (SELECT COUNT(*) FROM table_name)/2;
And if you want to filter by the row number:
SELECT t.* except (rn)
FROM (
SELECT t.*, ROW_NUMBER() OVER () AS rn
FROM table_name as t
) AS t
WHERE t.rn <= (SELECT COUNT(*) FROM table_name)/2;
To scale up, you can use an approx algorithm to find the 50% point:
DECLARE mid_date TIMESTAMP DEFAULT (
SELECT APPROX_QUANTILES(creation_date, 2)[OFFSET(1)] mid_date
FROM `fh-bigquery.stackoverflow_archive.201909_posts_answers` )
;
SELECT mid_date
, COUNTIF(creation_date > mid_date) first_half
, COUNTIF(creation_date < mid_date) second_half
FROM `fh-bigquery.stackoverflow_archive.201909_posts_answers`
Looks like it works well:
Now let's get these records out:
CREATE TABLE `temp.fifty_percent`
AS
SELECT *
FROM `fh-bigquery.stackoverflow_archive.201909_posts_answers`
WHERE creation_date < (
SELECT APPROX_QUANTILES(creation_date, 2)[OFFSET(1)] mid_date
FROM `fh-bigquery.stackoverflow_archive.201909_posts_answers`
)
This method will happily scale, while solutions using OVER(ORDER BY) won't.
Table part
I need to select all from the rows where the first 7 characters of the Assoc.Ref column are the same on a specific day.
Result example
You need aggregation :
SELECT t.col
FROM table t
GROUP BY t.col
HAVING COUNT(*) > 1;
If you want exactly two rows for each then use COUNT(*) = 2 instead .
If you want all rows then you can use windows function :
SELECT t.*
FROM (SELECT t.*,
COUNT(*) OVER(PARTITION BY col) AS cnt
FROM table t
) t
WHERE t.cnt > 1;
EDIT : After made update on question you might need LEFT() :
SELECT t.*
FROM (SELECT t.*,
COUNT(*) OVER(PARTITION BY CAST(Date_created AS date), LEFT(associated_ref, 7)) AS cnt
FROM table t
) t
WHERE t.cnt > 1 AND CAST(t.Date_created AS date) = '2019-02-08';
If the Date_created has no time then no conversation is needed. Just use Date_created instead.
If I have two columns - an ID field and a score field that can take 10 possible values, how can I select 5 random rows per ID? I know I can select 5 random rows from a table by using the following:
select *, rand() as idx
from mytable
order by idx fetch first 5 rows only
but how about 5 rows per ID?
You can do this using row_number():
select t.*
from (select t.*,
row_number() over (partition by idx order by rand()) as seqnum
from mytable t
) t
where seqnum <= 5;
I am facing one issue in below query
CREATE TABLE #tmp(rowid int,settle_id int)
insert into #tmp
select top 100
case when row_number() over (order by settle_id) > 10 then row_number() over (order by settle_id) - 10 else row_number() over (order by settle_id) end as rowid,settle_id from student_id(nolock)
select * from #tmp
drop table #tmp
I want row id should start from 1 -> 10 everytime but for first two sets it start from 1->10 but there after it starts with 11.
Please let me know what i am missing.
Use the below query to get the expected result.
SELECT
CASE WHEN ((row_number() over(order by settle_id) % 10) = 0)
THEN 10
ELSE (row_number() over (ORDER BY settle_id) % 10)
END AS RowID, settle_id
FROM student
Try using modulo arithmetic:
select ((row_number() over (order by settle_id) - 1) % 10) + 1 as rowid, settle_id
from student;
Some databases use the mod() function instead of %.