How to update date column in partitions of n rows? - sql

I am trying to update my date field.
Table structure is like:
date id
2016-11-14 1
2016-11-14 2
2016-11-14 3
2016-11-14 4
-
-
-
2016-11-14 100
How to update first ten records with different date, second ten records with different date and so on?

UPDATE tbl t
SET "date" = date '2016-11-14' + sub.rn::int / 10 -- integer division
FROM (
SELECT id, row_number() OVER (ORDER BY id) AS rn
FROM tbl
) sub
WHERE t.id = sub.id;
The subquery computes a gapless row number, since nothing in your question says the id is actually guaranteed to be without gaps.
You can just add an integer to an actual date to add a days. (Forgot the cast to int in my first version.)
For timestamp use instead:
timestamp '2016-11-14' + interval '1 day' * (sub.rn / 10)

You could use a CASE
UPDATE yourTable
SET "date" = CASE WHEN id <= 10 then '2016-11-01'::timestamp
WHEN id <= 20 then '2016-11-02'::timestamp
....
WHEN id <= 100 then '2016-11-10'::timestamp
END;

Related

Count the number of the time records appears in 48 hrs- SQL

How do we select the count of the record that appears more than once in 48hrs?
for eg
ID DATE
1 9/24/2018
1 9/23/2018
1 9/20/2018
2 9/20/2018
ID 1 APPEARED MORE THAN ONCE IN 48 HOURS
please let me know how to write a sql query to do this
There are lots of ways, but I'd start with using LAG() and a date comparison. Assuming your DATE column is a date data-type?
WITH
entity_summary AS
(
SELECT
ID,
CASE
WHEN LAG("DATE") OVER (PARTITION BY ID ORDER BY "DATE") >= "DATE" - INTERVAL '2' DAY
THEN 1
ELSE 0
END
AS occurence_within_2_day
FROM
Table1
)
SELECT
ID,
SUM(occurence_within_2_day)
FROM
entity_summary
GROUP BY
ID
HAVING
SUM(occurence_within_2_day) >= 1

Grouping data in SQL by difference in column values

I have following data in my logs table in postgres table:
logid => int (auto increment)
start_time => bigint (stores epoch value)
inserted_value => int
Following is the data stored in the table (where start time actual is not a column, just displaying start_time value in UTC format in 24 hour format)
logid user_id start_time inserted_value start time actual
1 1 1518416562 15 12-Feb-2018 06:22:42
2 1 1518416622 8 12-Feb-2018 06:23:42
3 1 1518417342 9 12-Feb-2018 06:35:42
4 1 1518417402 12 12-Feb-2018 06:36:42
5 1 1518417462 18 12-Feb-2018 06:37:42
6 1 1518418757 6 12-Feb-2018 06:59:17
7 1 1518418808 11 12-Feb-2018 07:00:08
I want to group and sum values according to difference in start_time
For above data, sum should be calculated in three groups:
user_id sum
1 15 + 8
1 9 + 12 + 18
1 6 + 11
So, values in each group has 1 minute difference. This 1 can be considered as any x minutes difference.
I was also trying LAG function but could not understand it fully. I hope I'm able to explain my question.
You can use a plain group by to achieve what you want. Just make all start_time values equal that belong to the same minute. For example
select user_id, start_time/60, sum(inserted_value)
from log_table
group by user_id, start_time/60
I assume your start_time column contains integers representing milliseconds, so /60 will properly truncate them to minutes. If the values are floats, you should use floor(start_time/60).
If you also want to select a human readable date of the minute you're grouping, you can add to_timestamp((start_time/60)*60) to the select list.
You can use LAG to check if current row is > 60 seconds more than previous row and set group_changed (a virtual column) each time this happens.
In next step, use running sum over that column. This creates a group_number which you can use to group results in the third step.
WITH cte1 AS (
SELECT
testdata.*,
CASE WHEN start_time - LAG(start_time, 1, start_time) OVER (PARTITION BY user_id ORDER BY start_time) > 60 THEN 1 ELSE 0 END AS group_changed
FROM testdata
), cte2 AS (
SELECT
cte1.*,
SUM(group_changed) OVER (PARTITION BY user_id ORDER BY start_time) AS group_number
FROM cte1
)
SELECT user_id, SUM(inserted_value)
FROM cte2
GROUP BY user_id, group_number
SQL Fiddle

Oracle get the last date for one month

I am not very good with Queries and Database.
I have the the following data table
Date ID Value
20160601 1 300
20160607 1 301
20160601 2 600
20160607 2 601
20160501 1 250
20160507 1 240
20160501 2 800
20160507 2 801
my requirement is to select the last date of a given month for each ID and show the value.
for example, If I choose month 5 the result would be:
Date ID Value
20160507 1 240
20160507 2 801
and so on based on the month the user will enter.
I know it may look simple but I am really stuck and I would appreciate some help. Thanks.
Assuming date is an actual date column (as it should be), you can use extract to compare the month value, and then the row_number() over ... analytic function to get the latest row per id value:
select date, id, value
from (select date, id, value,
row_number() over (partition by id order by date desc) as rn
from tbl
where extract(month from date) = 5)
where rn = 1
Of course, I assume that your actual date column is called something else, as date is a reserved word.
Find the maximum date then select all rows with that date.
select *
from table
where date = (select max(date) from table where date like '201605%')

Counting an already counted column in SQL (db2)

I'm pretty new to SQL and have this problem:
I have a filled table with a date column and other not interesting columns.
date | name | name2
2015-03-20 | peter | pan
2015-03-20 | john | wick
2015-03-18 | harry | potter
What im doing right now is counting everything for a date
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
what i want to do now is counting the resulting lines and only returning them if there are less then 10 resulting lines.
What i tried so far is surrounding the whole query with a temp table and the counting everything which gives me the number of resulting lines (yeah)
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
)
select count(*)
from temp_count
What is still missing the check if the number is smaller then 10.
I was searching in this Forum and came across some "having" structs to use, but that forced me to use a "group by", which i can't.
I was thinking about something like this :
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
)
select *
from temp_count
having count(*) < 10
maybe im too tired to think of an easy solution, but i can't solve this so far
Edit: A picture for clarification since my english is horrible
http://imgur.com/1O6zwoh
I want to see the 2 columned results ONLY IF there are less then 10 rows overall
I think you just need to move your having clause to the inner query so that it is paired with the GROUP BY:
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
having count(*) < 10
)
select *
from temp_count
If what you want is to know whether the total # of records (after grouping), are returned, then you could do this:
with temp_count (date, counter) as
(
select date, counter=count(*)
from testtable
where date >= current date - 10 days
group by date
)
select date, counter
from (
select date, counter, rseq=row_number() over (order by date)
from temp_count
) x
group by date, counter
having max(rseq) >= 10
This will return 0 rows if there are less than 10 total, and will deliver ALL the results if there are 10 or more (you can just get the first 10 rows if needed with this also).
In your temp_count table, you can filter results with the WHERE clause:
with temp_count (date, counter) as
(
select date, count(distinct date)
from testtable
where date >= current date - 10 days
group by date
)
select *
from temp_count
where counter < 10
Something like:
with t(dt, rn, cnt) as (
select dt, row_number() over (order by dt) as rn
, count(1) as cnt
from testtable
where dt >= current date - 10 days
group by dt
)
select dt, cnt
from t where 10 >= (select max(rn) from t);
will do what you want (I think)

SQL Oracle - Using RowNum in Query

I have two tables, examples as follows.
table_1
days special_day
10/09/2013 Y
10/10/2013 N
10/11/2013 Y
10/12/2013 N
10/13/2013 N
10/14/2013 Y
table_2
id special_day_ind numdays order
123 Y 3 2
456 N 5 1
My query would have to select the difference between sysday and the correct date from table_1 based on the parameters in table_2. If special_day_ind is 'Y', then I need 3 (numdays) special_days back from sysdate. If 'N', the numdays is the answer. Results would be ORDER(ed) BY order asc(ending).
In the above tables example, the query would return back.
sysdate = 10/14/2013
id days
456 5
123 5 (10/14/2013 - 10/9/2013)
It seems like ROWNUM would do the trick, however with the differing 'ways' of counting, I'm not sure how to proceed.
Here's a way to do it.
You need to assign a row number to special days in table_1.
select days,
row_number() over (order by days desc) r
from table_1
where special_day = 'Y';
Using this as CTE, you can find the earlier special days and subtract it from the sysdate.
with x as(
select days,
row_number() over (order by days desc) r
from table_1
where special_day = 'Y'
)
select id,
case when special_day_ind = 'N'
then numdays
when special_day_ind = 'Y'
then trunc(sysdate) - (select days
from x
where r = numdays)
end days
from table_2
order by order_;
Demo.