postgres find matched and unmatched records - postgresql

I have two table
offline_tbl
cen | subcen
------------
01 | 002
------------
02 | 001
------------
02 | 003
------------
03 | 001
------------
03 | 009
------------
online_tbl
cen | subcen
------------
01 | 002
------------
02 | 001
------------
02 | 004
------------
03 | 001
------------
03 | 008
------------
04 | 079
------------
05 | 006
------------
I have two Table offline_tbl and online_tbl. I would like to match offline_tbl cen and subcen with online_tbl cen and subcen.
records which are either present in offline_tbl or online_tbl , but not in both tables.
my expected output
cen | subcen
------------
02 | 003
------------
02 | 004
------------
03 | 008
------------
03 | 009
------------
04 | 079
------------
05 | 006
------------

Use full join:
select
a.cen as offline_cen,
a.subcen as offline_subcen,
b.cen as online_cen,
b.subcen as online_subcen
from offline_tbl a
full join online_tbl b
on a.cen = b.cen and a.subcen = b.subcen
offline_cen | offline_subcen | online_cen | online_subcen
-------------+----------------+------------+---------------
01 | 002 | 01 | 002
02 | 001 | 02 | 001
02 | 003 | |
| | 02 | 004
03 | 001 | 03 | 001
| | 03 | 008
03 | 009 | |
| | 04 | 079
| | 05 | 006
(9 rows)
If you want to get only values present in one of the tables:
select
coalesce(a.cen, b.cen) as cen,
coalesce(a.subcen, b.subcen) as subcen
from offline_tbl a
full join online_tbl b
on a.cen = b.cen and a.subcen = b.subcen
where a.cen is null or b.cen is null
cen | subcen
-----+--------
02 | 003
02 | 004
03 | 008
03 | 009
04 | 079
05 | 006
(6 rows)

Related

ERROR: control reached end of trigger procedure without RETURN

I am learning how to make functions and triggers and I cannot get them to work. Here are all the relevant tables:
Table: "cust"
cust_id | email
------- | -----
1 | jack.daniels#google.com
2 | jose.quervo#yahoo.com
3 | jim.beam#protonmail.com
Table: "inv"
fm_id | inv_id
----- |--------
22 | 10
23 | 11
24 | 12
25 | 13
26 | 14
27 | 15
28 | 16
29 | 17
30 | 18
31 | 19
31 | 20
32 | 21
Table: "rent"
inv_id | cust_id | rent_dt
------ |-------- | --------
10 | 1 | 9/1/2022 10:29
11 | 1 | 9/2/2022 18:16
12 | 1 | 9/2/2022 18:17
13 | 1 | 9/17/2022 17:34
14 | 1 | 9/19/2022 6:32
15 | 1 | 9/19/2022 6:33
16 | 3 | 9/1/2022 18:45
17 | 3 | 9/1/2022 18:46
18 | 3 | 9/2/2022 18:45
19 | 3 | 9/2/2022 18:46
20 | 3 | 9/17/2022 18:32
21 | 3 | 9/19/2022 22:12
10 | 2 | 9/19/2022 11:43
11 | 2 | 9/19/2022 11:42
Table: "fm"
fm_id | titl
----- | -----
22 | Anaconda
23 | Exorcist
24 | Philadelphia
25 | Quest
26 | Sweden
27 | Speed
28 | Nemo
29 | Zoolander
30 | Truman
31 | Patient
32 | Racer
Table: "d_rpt"
cust_id | email | fm_id | inv_id | rent_dt
------- | ------------------------- | ----- | ------ | --------
1 | jack.daniels#google.com | 10 | 22 | 9/1/2022 10:29
1 | jack.daniels#google.com | 11 | 23 | 9/2/2022 18:16
1 | jack.daniels#google.com | 12 | 24 | 9/2/2022 18:17
1 | jack.daniels#google.com | 13 | 25 | 9/17/2022 17:34
1 | jack.daniels#google.com | 14 | 26 | 9/19/2022 6:32
1 | jack.daniels#google.com | 15 | 27 | 9/19/2022 6:33
2 | jose.quervo#yahoo.com | 10 | 22 | 9/19/2022 11:43
2 | jose.quervo#yahoo.com | 11 | 23 | 9/19/2022 11:42
3 | jim.beam#protonmail.com | 16 | 28 | 9/1/2022 18:45
3 | jim.beam#protonmail.com | 17 | 29 | 9/1/2022 18:46
3 | jim.beam#protonmail.com | 18 | 30 | 9/2/2022 18:45
3 | jim.beam#protonmail.com | 19 | 31 | 9/2/2022 18:46
3 | jim.beam#protonmail.com | 20 | 31 | 9/17/2022 18:32
3 | jim.beam#protonmail.com | 21 | 32 | 9/19/2022 22:12
Table: "sm_rpt"
email | rd_cnt
------------------------ | ------
jack.daniels#google.com | 6
jim.beam#protonmail.com | 6
When a insert statement is run on the 'd_rpt' table the trigger should fire and run the truncate/insert/select statement for the the 'sm_rpt' table. Here are the trigger function and trigger statement:
Trigger Function:
CREATE FUNCTION ins_trig_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS
$$
BEGIN
TRUNCATE FROM sm_rpt;
INSERT INTO sm_rpt
SELECT
cust.email,
count (DISTINCT inv.fm_id) AS "rd_cnt"
FROM cust
INNER JOIN rent ON rent.cust_id = cust.cust_id
INNER JOIN inv ON inv.inv_id = rent.inv_id
INNER JOIN fm ON fm.fm_id = inv.fm_id
WHERE rent.rent_dt BETWEEN '2005-08-01' AND '2005-08-31'
GROUP BY cust.email
ORDER BY "rd_cnt" DESC;
END;
$$
Trigger statement:
CREATE TRIGGER nw_wn
AFTER INSERT
ON d_rpt
FOR EACH STATEMENT
EXECUTE PROCEDURE ins_trig_func();
I get success when creating both the trigger function and trigger statement from that. However when I go to test it out by truncating and then inserting new data, on the 'd_rpt' table, I get an error for the trigger and that is what I cannot solve. Here is that error:
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function insert_trigger_function()
SQL state: 2F005
Any help you can offer would be greatly appreciated.
PS.
I did not include the truncate and insert commands that I use because I have already verified they work fine outside of trying to implement this trigger. The issue I think has to lie in the trigger function but the search feature and google are not my friend in trying to identify specifically what.
**
EDITS To the above are found below here
**
OK, I have solved it now with both of your help. Thank you so much Belayer
and Adrian Klaver !!!!
CREATE FUNCTION ins_trig_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS
$$
BEGIN
TRUNCATE FROM sm_rpt;
INSERT INTO sm_rpt
SELECT
cust.email,
count (DISTINCT inv.fm_id) AS "rd_cnt"
FROM cust
INNER JOIN rent ON rent.cust_id = cust.cust_id
INNER JOIN inv ON inv.inv_id = rent.inv_id
INNER JOIN fm ON fm.fm_id = inv.fm_id
WHERE rent.rent_dt BETWEEN '2005-08-01' AND '2005-08-31'
GROUP BY cust.email
RETURN NULL;
END;
$$

Finding the end date from asynchronous starting but consecutive running date ranges

I need to help with a database model and and efficient calculation method of the last end date.
The ranges have a start date but will wait to start until the currently active ranges have ended. Changing the length or start of one range should cascade to the waiting ranges and push them back. But they can never start before their start date.
The database mock here is just to explain the problem and doesn't need to be followed as long as it works properly.
| id | start | length | 01 02 03 04 05 06 07 08 09 10 11 12 |
| 1 | 03 | 2 | ------ |
| 2 | 06 | 2 | ------ |
I am aware that I can brute force the answer to get the last date. But I'm looking for a more efficient solution as there are many ranges and the end date needs to read often.
Also is this something that's possible to calculate in a PostgreSQL query? Or maybe keep end date fields up to date with triggers?
Examples
Here range 2 starts on 04 but can't be used until after range 1 finishes.
| id | start | length | 01 02 03 04 05 06 07 08 09 10 11 12 |
| 1 | 02 | 5 | ------------------ |
| 2 | 04 | 5 | ------------------ |
If we update the range 1, range 2 should move up with it.
| id | start | length | 01 02 03 04 05 06 07 08 09 10 11 12 |
| 1 | 02 | 4 | -------------- |
| 2 | 04 | 5 | ------------------ |
But range 2 shouldn't move past its start date.
| id | start | length | 01 02 03 04 05 06 07 08 09 10 11 12 |
| 1 | 02 | 1 | -- |
| 2 | 04 | 5 | ------------------ |
If you just take the latest start date and add its duration you will get the wrong answer.
| id | start | length | 01 02 03 04 05 06 07 08 09 10 11 12 |
| 1 | 04 | 5 | ------------------ |
| 2 | 05 | 2 | ------ |
Get: 7
Expected: 10

Get previous days' value in column in postgres

I have a question.
I have a sql command that is getting the moving average for each day using window functions.
BEGIN;
DROP TABLE IF EXISTS vol_stats;
SELECT pk as fk,
avg(CAST(volume as FLOAT)) over (partition by account_id order by "endts") as average,
INTO vol_stats
from volume_temp
order by account_id, "endts";
COMMIT;
I would like to get one more value and that is the previous days' value.
The data structure looks like this.
acccount_id | value | timestamp
-------------------------------
a12 | 122 | jan 1
a13 | 133 | jan 1
a14 | 443 | jan 1
a12 | 251 | jan 2
a13 | 122 | jan 2
a14 | 331 | jan 2
a12 | 412 | jan 3
a13 | 323 | jan 3
a14 | 432 | jan 3
and we are computing this
acccount_id | value | timestamp | Average
-----------------------------------------
a12 | 122 | jan 1 | 122
a13 | 133 | jan 1 | 133
a14 | 443 | jan 1 | 443
a12 | 251 | jan 2 | 188.5
a13 | 122 | jan 2 | 222.5
a14 | 331 | jan 2 | 387
a12 | 412 | jan 3 | 261.6
a13 | 323 | jan 3 | 192.6
a14 | 432 | jan 3 | 402
What would be helpful would be to grab the previous days' value as well. Like this.
acccount_id | value | timestamp | Average | previous
-----------------------------------------
a12 | 122 | jan 1 | 122 | null
a13 | 133 | jan 1 | 133 | null
a14 | 443 | jan 1 | 443 | null
a12 | 251 | jan 2 | 188.5 | 122
a13 | 122 | jan 2 | 222.5 | 133
a14 | 331 | jan 2 | 387 | 443
a12 | 412 | jan 3 | 261.6 | 251
a13 | 323 | jan 3 | 192.6 | 122
a14 | 432 | jan 3 | 402 | 331
Just add another column to the SELECT list:
lag(volume) OVER (PARTITION BY account_id ORDER BY endts)

Window function to achieve running sum that resets in Postgres SQL [duplicate]

I wrote a query that creates two columns: the_day, and the amount_raised on that day. Here is what I have:
And I would like to add a column that has a running sum of amount_raised:
Ultimately, I would like the sum column to reset after it reaches 1 million.
The recursive approach is above my pay grade, so if anyone knows a way to reset the sum without creating an entirely new table, please comment (maybe with a RESET function?). Thank you
I'd like to thank Juan Carlos Oropeza for providing a script and SQLFiddle with the test data. George, you should have done that.
The query itself it rather simple.
At first calculate a simple running sum (CTE_RunningSum) and divide it by 1,000,000 to get number of whole millions.
Then calculate the running sum again with partitioning by the number of millions.
SQL Fiddle
I included the columns RunningSum and Millions in the final result to illustrate how the query works.
WITH
CTE_RunningSum
AS
(
SELECT
ID
,day_t
,collect
,SUM(collect) OVER(ORDER BY day_t, id) AS RunningSum
,(SUM(collect) OVER(ORDER BY day_t, id)) / 1000000 AS Millions
FROM myTable
)
SELECT
ID
,day_t
,collect
,RunningSum
,Millions
,SUM(collect) OVER(PARTITION BY Millions ORDER BY day_t, id) AS Result
FROM CTE_RunningSum
ORDER BY day_t, id;
Result
| id | day_t | collect | runningsum | millions | result |
|-----|-----------------------------|---------|------------|----------|---------|
| 90 | March, 11 2015 00:00:00 | 69880 | 69880 | 0 | 69880 |
| 13 | March, 25 2015 00:00:00 | 69484 | 139364 | 0 | 139364 |
| 49 | March, 27 2015 00:00:00 | 57412 | 196776 | 0 | 196776 |
| 41 | March, 30 2015 00:00:00 | 56404 | 253180 | 0 | 253180 |
| 99 | April, 03 2015 00:00:00 | 59426 | 312606 | 0 | 312606 |
| 1 | April, 10 2015 00:00:00 | 65825 | 378431 | 0 | 378431 |
| 100 | April, 27 2015 00:00:00 | 60884 | 439315 | 0 | 439315 |
| 50 | May, 11 2015 00:00:00 | 39641 | 478956 | 0 | 478956 |
| 58 | May, 11 2015 00:00:00 | 49759 | 528715 | 0 | 528715 |
| 51 | May, 17 2015 00:00:00 | 32895 | 561610 | 0 | 561610 |
| 15 | May, 19 2015 00:00:00 | 50847 | 612457 | 0 | 612457 |
| 66 | May, 29 2015 00:00:00 | 66332 | 678789 | 0 | 678789 |
| 4 | June, 04 2015 00:00:00 | 46891 | 725680 | 0 | 725680 |
| 38 | June, 09 2015 00:00:00 | 64732 | 790412 | 0 | 790412 |
| 79 | June, 14 2015 00:00:00 | 62843 | 853255 | 0 | 853255 |
| 37 | June, 28 2015 00:00:00 | 54315 | 907570 | 0 | 907570 |
| 59 | June, 30 2015 00:00:00 | 34885 | 942455 | 0 | 942455 |
| 71 | July, 08 2015 00:00:00 | 46440 | 988895 | 0 | 988895 |
| 31 | July, 10 2015 00:00:00 | 39649 | 1028544 | 1 | 39649 |
| 91 | July, 12 2015 00:00:00 | 65048 | 1093592 | 1 | 104697 |
| 57 | July, 14 2015 00:00:00 | 60394 | 1153986 | 1 | 165091 |
| 98 | July, 20 2015 00:00:00 | 34481 | 1188467 | 1 | 199572 |
| 3 | July, 26 2015 00:00:00 | 58672 | 1247139 | 1 | 258244 |
| 95 | August, 19 2015 00:00:00 | 52393 | 1299532 | 1 | 310637 |
| 74 | August, 20 2015 00:00:00 | 37972 | 1337504 | 1 | 348609 |
| 20 | August, 27 2015 00:00:00 | 36882 | 1374386 | 1 | 385491 |
| 2 | September, 07 2015 00:00:00 | 39408 | 1413794 | 1 | 424899 |
| 14 | September, 09 2015 00:00:00 | 40234 | 1454028 | 1 | 465133 |
| 6 | September, 17 2015 00:00:00 | 65957 | 1519985 | 1 | 531090 |
| 93 | September, 29 2015 00:00:00 | 47213 | 1567198 | 1 | 578303 |
| 35 | September, 30 2015 00:00:00 | 49446 | 1616644 | 1 | 627749 |
| 86 | October, 11 2015 00:00:00 | 34291 | 1650935 | 1 | 662040 |
| 75 | October, 12 2015 00:00:00 | 31448 | 1682383 | 1 | 693488 |
| 19 | October, 14 2015 00:00:00 | 48509 | 1730892 | 1 | 741997 |
| 56 | October, 26 2015 00:00:00 | 30072 | 1760964 | 1 | 772069 |
| 48 | October, 28 2015 00:00:00 | 58527 | 1819491 | 1 | 830596 |
| 40 | November, 05 2015 00:00:00 | 67293 | 1886784 | 1 | 897889 |
| 33 | November, 09 2015 00:00:00 | 41944 | 1928728 | 1 | 939833 |
| 34 | November, 11 2015 00:00:00 | 35516 | 1964244 | 1 | 975349 |
| 85 | November, 20 2015 00:00:00 | 43920 | 2008164 | 2 | 43920 |
| 18 | November, 23 2015 00:00:00 | 44925 | 2053089 | 2 | 88845 |
| 62 | December, 24 2015 00:00:00 | 34678 | 2087767 | 2 | 123523 |
| 67 | December, 25 2015 00:00:00 | 35323 | 2123090 | 2 | 158846 |
| 81 | December, 28 2015 00:00:00 | 37071 | 2160161 | 2 | 195917 |
| 54 | January, 02 2016 00:00:00 | 32330 | 2192491 | 2 | 228247 |
| 70 | January, 06 2016 00:00:00 | 47875 | 2240366 | 2 | 276122 |
| 28 | January, 23 2016 00:00:00 | 40250 | 2280616 | 2 | 316372 |
| 65 | January, 25 2016 00:00:00 | 49404 | 2330020 | 2 | 365776 |
| 73 | January, 26 2016 00:00:00 | 65879 | 2395899 | 2 | 431655 |
| 5 | February, 05 2016 00:00:00 | 53953 | 2449852 | 2 | 485608 |
| 32 | February, 11 2016 00:00:00 | 44988 | 2494840 | 2 | 530596 |
| 53 | February, 25 2016 00:00:00 | 68948 | 2563788 | 2 | 599544 |
| 83 | March, 11 2016 00:00:00 | 47244 | 2611032 | 2 | 646788 |
| 8 | March, 25 2016 00:00:00 | 51809 | 2662841 | 2 | 698597 |
| 82 | March, 25 2016 00:00:00 | 66506 | 2729347 | 2 | 765103 |
| 88 | April, 06 2016 00:00:00 | 69288 | 2798635 | 2 | 834391 |
| 89 | April, 14 2016 00:00:00 | 43162 | 2841797 | 2 | 877553 |
| 52 | April, 23 2016 00:00:00 | 47772 | 2889569 | 2 | 925325 |
| 7 | April, 27 2016 00:00:00 | 33368 | 2922937 | 2 | 958693 |
| 84 | April, 27 2016 00:00:00 | 57644 | 2980581 | 2 | 1016337 |
| 17 | May, 17 2016 00:00:00 | 35416 | 3015997 | 3 | 35416 |
| 61 | May, 17 2016 00:00:00 | 64603 | 3080600 | 3 | 100019 |
| 87 | June, 07 2016 00:00:00 | 41865 | 3122465 | 3 | 141884 |
| 97 | June, 08 2016 00:00:00 | 64982 | 3187447 | 3 | 206866 |
| 92 | June, 15 2016 00:00:00 | 58684 | 3246131 | 3 | 265550 |
| 23 | June, 26 2016 00:00:00 | 46147 | 3292278 | 3 | 311697 |
| 46 | June, 30 2016 00:00:00 | 61921 | 3354199 | 3 | 373618 |
| 94 | July, 03 2016 00:00:00 | 55535 | 3409734 | 3 | 429153 |
| 60 | July, 07 2016 00:00:00 | 63607 | 3473341 | 3 | 492760 |
| 45 | July, 20 2016 00:00:00 | 51965 | 3525306 | 3 | 544725 |
| 96 | July, 20 2016 00:00:00 | 46684 | 3571990 | 3 | 591409 |
| 29 | August, 09 2016 00:00:00 | 37707 | 3609697 | 3 | 629116 |
| 69 | August, 11 2016 00:00:00 | 37194 | 3646891 | 3 | 666310 |
| 80 | August, 19 2016 00:00:00 | 62673 | 3709564 | 3 | 728983 |
| 36 | August, 28 2016 00:00:00 | 48237 | 3757801 | 3 | 777220 |
| 39 | August, 29 2016 00:00:00 | 48159 | 3805960 | 3 | 825379 |
| 25 | August, 30 2016 00:00:00 | 60958 | 3866918 | 3 | 886337 |
| 68 | September, 04 2016 00:00:00 | 50167 | 3917085 | 3 | 936504 |
| 55 | September, 08 2016 00:00:00 | 31193 | 3948278 | 3 | 967697 |
| 64 | September, 10 2016 00:00:00 | 31157 | 3979435 | 3 | 998854 |
| 42 | September, 14 2016 00:00:00 | 52878 | 4032313 | 4 | 52878 |
| 43 | September, 15 2016 00:00:00 | 54728 | 4087041 | 4 | 107606 |
| 77 | September, 18 2016 00:00:00 | 65320 | 4152361 | 4 | 172926 |
| 12 | September, 23 2016 00:00:00 | 43597 | 4195958 | 4 | 216523 |
| 30 | September, 26 2016 00:00:00 | 32764 | 4228722 | 4 | 249287 |
| 10 | September, 27 2016 00:00:00 | 47038 | 4275760 | 4 | 296325 |
| 47 | October, 08 2016 00:00:00 | 46280 | 4322040 | 4 | 342605 |
| 26 | October, 10 2016 00:00:00 | 69487 | 4391527 | 4 | 412092 |
| 63 | October, 30 2016 00:00:00 | 49561 | 4441088 | 4 | 461653 |
| 78 | November, 15 2016 00:00:00 | 40138 | 4481226 | 4 | 501791 |
| 27 | November, 27 2016 00:00:00 | 57378 | 4538604 | 4 | 559169 |
| 21 | December, 01 2016 00:00:00 | 35336 | 4573940 | 4 | 594505 |
| 16 | December, 03 2016 00:00:00 | 39671 | 4613611 | 4 | 634176 |
| 22 | December, 13 2016 00:00:00 | 34574 | 4648185 | 4 | 668750 |
| 72 | January, 29 2017 00:00:00 | 55084 | 4703269 | 4 | 723834 |
| 44 | January, 30 2017 00:00:00 | 36742 | 4740011 | 4 | 760576 |
| 24 | February, 01 2017 00:00:00 | 31061 | 4771072 | 4 | 791637 |
| 76 | February, 12 2017 00:00:00 | 35059 | 4806131 | 4 | 826696 |
| 9 | February, 27 2017 00:00:00 | 39767 | 4845898 | 4 | 866463 |
| 11 | February, 28 2017 00:00:00 | 66007 | 4911905 | 4 | 932470 |
I took a look again and couldnt solve it with a Windows Function so I took the recursive aproach
SQL Fiddle Demo
Sample Data: 100 rows random dates between 2015-2017 amounts between 10k - 70k
DROP TABLE IF EXISTS "myTable";
CREATE TABLE "myTable" (
id SERIAL PRIMARY KEY,
day_t varchar(255),
collect integer NULL
);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-04-10',65825),('2015-09-07',39408),('2015-07-26',58672),('2015-06-04',46891),('2016-02-05',53953),('2015-09-17',65957),('2016-04-27',33368),('2016-03-25',51809),('2017-02-27',39767),('2016-09-27',47038);
INSERT INTO "myTable" (day_t,collect) VALUES ('2017-02-28',66007),('2016-09-23',43597),('2015-03-25',69484),('2015-09-09',40234),('2015-05-19',50847),('2016-12-03',39671),('2016-05-17',35416),('2015-11-23',44925),('2015-10-14',48509),('2015-08-27',36882);
INSERT INTO "myTable" (day_t,collect) VALUES ('2016-12-01',35336),('2016-12-13',34574),('2016-06-26',46147),('2017-02-01',31061),('2016-08-30',60958),('2016-10-10',69487),('2016-11-27',57378),('2016-01-23',40250),('2016-08-09',37707),('2016-09-26',32764);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-07-10',39649),('2016-02-11',44988),('2015-11-09',41944),('2015-11-11',35516),('2015-09-30',49446),('2016-08-28',48237),('2015-06-28',54315),('2015-06-09',64732),('2016-08-29',48159),('2015-11-05',67293);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-03-30',56404),('2016-09-14',52878),('2016-09-15',54728),('2017-01-30',36742),('2016-07-20',51965),('2016-06-30',61921),('2016-10-08',46280),('2015-10-28',58527),('2015-03-27',57412),('2015-05-11',39641);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-05-17',32895),('2016-04-23',47772),('2016-02-25',68948),('2016-01-02',32330),('2016-09-08',31193),('2015-10-26',30072),('2015-07-14',60394),('2015-05-11',49759),('2015-06-30',34885),('2016-07-07',63607);
INSERT INTO "myTable" (day_t,collect) VALUES ('2016-05-17',64603),('2015-12-24',34678),('2016-10-30',49561),('2016-09-10',31157),('2016-01-25',49404),('2015-05-29',66332),('2015-12-25',35323),('2016-09-04',50167),('2016-08-11',37194),('2016-01-06',47875);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-07-08',46440),('2017-01-29',55084),('2016-01-26',65879),('2015-08-20',37972),('2015-10-12',31448),('2017-02-12',35059),('2016-09-18',65320),('2016-11-15',40138),('2015-06-14',62843),('2016-08-19',62673);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-12-28',37071),('2016-03-25',66506),('2016-03-11',47244),('2016-04-27',57644),('2015-11-20',43920),('2015-10-11',34291),('2016-06-07',41865),('2016-04-06',69288),('2016-04-14',43162),('2015-03-11',69880);
INSERT INTO "myTable" (day_t,collect) VALUES ('2015-07-12',65048),('2016-06-15',58684),('2015-09-29',47213),('2016-07-03',55535),('2015-08-19',52393),('2016-07-20',46684),('2016-06-08',64982),('2015-07-20',34481),('2015-04-03',59426),('2015-04-27',60884);
Create a row_number to perform the recursion need consecutive ID's
CREATE TABLE sortDates as
SELECT day_t,
collect,
row_number() over (order by day_t) rn
FROM "myTable";
Recursive Query
If you see the CASE if previous total m.collect is bigger than 1 million the total is reset.
WITH RECURSIVE million(rn, day_t, collect) AS (
(
SELECT rn, day_t, collect
FROM sortDates
WHERE rn = 1
)
UNION
(
SELECT s.rn, s.day_t, CASE WHEN m.collect > 1000000 THEN s.collect
ELSE m.collect + s.collect
END as collect
FROM sortDates s
JOIN million m
ON s.rn = m.rn + 1
)
)
SELECT *
FROM million
WHERE collect > 1000000
Finally just bring the rows where you break the 1 million limit.
OUTPUT
| rn | day_t | collect |
|----|------------|---------|
| 19 | 2015-07-10 | 1028544 |
| 41 | 2015-11-23 | 1024545 |
| 62 | 2016-05-17 | 1027511 |
| 82 | 2016-09-15 | 1006441 |

PostgreSQL : LEFT JOIN with tempory table adding extra lines

I have a view storing water pipes references together with details on operations on the water system. I need to extract from that view the water pipes on which more than one operation were registered over the past 12 months. Here is how I proceed :
Here is the view structure and a sample of data:
CREATE TABLE schema.pipe (
id INTEGER,
code VARCHAR,
ope_date DATE,
ope_type VARCHAR(2),
system VARCHAR(2));
INSERT INTO schema.pipe (code, ope_date, ope_type, system) VALUES
('0001', '2014-11-11', '01', 'EU'),
('0001', '2014-11-11', '03', 'EU'),
('0002', '2014-12-03', '03', 'EP'),
('0002', '2014-01-03', '03', 'EP'),
('0003', '2014-08-11', '01', 'EP'),
('0003', '2014-03-03', '03', 'EP'),
('0003', '2012-02-27', '03', 'EP'),
('0004', '2014-08-11', '01', 'UN'),
('0004', '2013-12-30', '03', 'UN'),
('0004', '2013-06-01', '03', 'UN'),
('0004', '2012-07-31', '03', 'UN'),
('0005', '2013-10-01', '03', 'EU'),
('0005', '2012-11-01', '03', 'EU'),
('0006', '2014-04-01', '01', 'UN'),
('0006', '2014-05-15', '01', 'UN');
code is the pipe reference
ope_date is the operation date
ope_type is the operation type
system is the system type
Here is the query I'm using:
SELECT code, ope_date FROM schema.pipe
WHERE (NOW()::DATE - ope_date) < 365
GROUP BY code, ope_date
HAVING count(*) = 1 ;
I get this:
code | ope_date
---------+--------------
0002 | 2014-12-03
0002 | 2014-01-03
0003 | 2014-08-11
0003 | 2014-03-03
0004 | 2013-12-30
0004 | 2014-08-11
0006 | 2014-04-01
0006 | 2014-05-15
Now, I need to bring back the other columns with this selection. So I use:
WITH temptable AS (
SELECT code, ope_date FROM schema.pipe WHERE (NOW()::DATE - ope_date) < 365 GROUP BY code, ope_date HAVING count(*) = 1)
SELECT DISTINCT a.code, a.ope_date, b.ope_type, b.system FROM temptable a LEFT JOIN schema.pipe b on a.code = b.code ;
I get this, which is too many lines (I need 8 lines and I get 12):
code | ope_date | ope_type | system
-------+--------------+------------+---------
0002 | 2014-01-03 | 03 | EP
0002 | 2014-12-03 | 03 | EP
0003 | 2014-03-03 | 01 | EP
0003 | 2014-03-03 | 03 | EP
0003 | 2014-08-11 | 01 | EP
0003 | 2014-08-11 | 03 | EP
0004 | 2013-12-30 | 01 | UN
0004 | 2013-12-30 | 03 | UN
0004 | 2014-08-11 | 01 | UN
0004 | 2014-08-11 | 03 | UN
0006 | 2014-04-01 | 01 | UN
0006 | 2014-05-15 | 01 | UN
So here comes my question: how can I get just the lines matching my selection?
Many thanks in advance.
EDIT :
What I need is:
code | ope_date | ope_type | system
---------+-------------+-----------+---------
0002 | 2014-12-03 | 03 | EP
0002 | 2014-01-03 | 03 | EP
0003 | 2014-08-11 | 01 | EP
0003 | 2014-03-03 | 03 | EP
0004 | 2013-12-30 | 03 | UN
0004 | 2014-08-11 | 01 | UN
0006 | 2014-04-01 | 01 | UN
0006 | 2014-05-15 | 01 | UN
I've found myself a solution that consists in using both code and ope_date columns to join the tables (not just code):
WITH temptable AS (
SELECT code, ope_date FROM schema.pipe WHERE (NOW()::DATE - ope_date) < 365 GROUP BY code, ope_date HAVING count(*) = 1)
SELECT DISTINCT a.code, a.ope_date, b.ope_type, b.system FROM temptable a, schema.pipe b WHERE a.code = b.code AND a.ope_date = b.ope_date;
Any comment on this solution?