CTE - recursive query doing too much - sql

I have the current table of data...
| LoanRollupID | NewLoanID | PreviousLoanID |
|--------------|-----------|----------------|
| 11 | 76 | 44 |
| 12 | 80 | 75 |
| 13 | 83 | 82 |
| 14 | 84 | 83 |
| 15 | 86 | 85 |
| 16 | 87 | 54 |
| 17 | 88 | 87 |
| 18 | 90 | 48 |
| 19 | 91 | 34 |
| 20 | 93 | 41 |
| 21 | 94 | 76 |
| 22 | 95 | 90 |
| 23 | 96 | 94 |
| 24 | 100 | 92 |
| 25 | 101 | 99 |
| 26 | 102 | 98 |
| 27 | 103 | 101 |
| 28 | 104 | 81 |
| 29 | 105 | 80 |
| 30 | 107 | 52 |
| 31 | 110 | 108 |
| 1029 | 1105 | 103 |
| 1030 | 1106 | 104 |
| 1031 | 1108 | 1106 |
| 1032 | 1109 | 73 |
I'm trying to jump in at NewLoanID 1108 and see how it has evolved from previous Loans. e.g 1108 came from 1106, which came from 104, which came from 81, etc.
When I run this query:
WITH OldLoans (PreviousLoanID, NewLoanID, start)
AS
(
---- Anchor member definition
SELECT l.NewLoanID, l.PreviousLoanID, 0 as start
FROM dscs_public.LoanRollup l
Where NewLoanID = 1108
UNION ALL
-- Recursive member definition
SELECT l.NewLoanID, l.PreviousLoanID, start + 1
FROM dscs_public.LoanRollup l
INNER JOIN OldLoans AS o
ON o.NewLoanID = l.PreviousLoanID
)
---- Statement that executes the CTE
SELECT PreviousLoanID, NewLoanID, start
FROM OldLoans
It fails with this error:
The statement terminated. The maximum recursion 100 has been exhausted
before statement completion.
Can anyone spot my mistake please?
Thanks.

The aliases in the CTE definition are in the wrong order:
-- Instead of (PreviousLoanID, NewLoanID, start)
WITH OldLoans (NewLoanID, PreviousLoanID, start)
AS
(
---- Anchor member definition
SELECT l.NewLoanID, l.PreviousLoanID, 0 as start
FROM mytable l --LoanRollup l
Where NewLoanID = 1108
UNION ALL
-- Recursive member definition
SELECT l.NewLoanID, l.PreviousLoanID, start + 1
FROM mytable l --dscs_public.LoanRollup l
INNER JOIN OldLoans AS o
-- Instead of o.NewLoanID = l.PreviousLoanID
ON l.NewLoanID = o.PreviousLoanID
)
---- Statement that executes the CTE
SELECT PreviousLoanID, NewLoanID, start
FROM OldLoans
The same thing holds for the ON clause in the recursive member definition.

Related

Select All rows WHERE ARRAY = "type"

I have a problem with a PostgreSQL query.
I have a table named "pokemons" with different columns :
id | name | pv | attaque | defense | attaque_spe | defense_spe | vitesse | type
-----+------------+-----+---------+---------+-------------+-------------+---------+------------------
1 | Bulbizarre | 45 | 49 | 49 | 65 | 65 | 45 | {Plante,Poison}
2 | Herbizarre | 60 | 62 | 63 | 80 | 80 | 60 | {Plante,Poison}
3 | Florizarre | 80 | 82 | 83 | 100 | 100 | 80 | {Plante,Poison}
4 | Salameche | 39 | 52 | 43 | 60 | 50 | 65 | {Feu}
5 | Reptincel | 58 | 64 | 58 | 80 | 65 | 80 | {Feu}
6 | Dracaufeu | 78 | 84 | 78 | 109 | 85 | 100 | {Feu,Vol}
7 | Carapuce | 44 | 48 | 65 | 50 | 64 | 43 | {Eau}
8 | Carabaffe | 59 | 63 | 80 | 65 | 80 | 58 | {Eau}
9 | Tortank | 79 | 83 | 100 | 85 | 105 | 78 | {Eau}
In this table, I want to select all the rows with a specific type.
Kind of things, I did try :
SELECT * FROM pokemons WHERE 'feu'=ANY(type);
I tried many things with ALL or stuff like that but can't get a single a row.
Can you help me there please.
Thanks.
Adding to the solution mentioned in the comment, you may also make a case insensitive comparison like this.
SELECT * FROM pokemons WHERE 'feu' ilike ANY(type);

SQL - Calculating cell-value based on other cell-values

So I have run into a problem when working on some SQL coding.
I have a data table that looks somewhat like this:
ID TimeID IndicatorID Score
1 111 45 20
1 111 46 14
1 111 47 83
1 111 48 91
1 112 45 20
1 112 46 14
1 112 47 83
1 112 48 91
2 111 45 25
2 111 46 12
2 111 47 70
2 111 48 82
2 112 45 25
2 112 46 12
2 112 47 70
2 112 48 82
I want to add new rows containing values for indicator 240 and 241 where the score for indicator 240 is the score for indicator 45 / score for indicator 46 and similarly the score for indicator 241 is the score for indicator 47/ score for indicator 48. This has to be done for each TimeID for each ID.
The full table is huge as the number of IDs, TimeIDs for each ID, and IndicatorIDs for each TimeID is large.
Assuming your requirements are as stated, and all the IndicatorID values are hard-coded this can be done with some simply sub-queries and a straightforward INSERT statement:
insert into your_table
with yt as (
select * from your_table where IndicatorID in (45,46,47,48)
)
, yt45 as (select * from yt where IndicatorID = 45 )
, yt46 as (select * from yt where IndicatorID = 46 )
, yt47 as (select * from yt where IndicatorID = 47 )
, yt48 as (select * from yt where IndicatorID = 48 )
select yt45.id
, yt45.timeID
, 240 as IndicatorID
, yt45.score/yt46.score as score
from yt45
join yt46
on yt45.id = yt46.id
and yt45.timeID = yt46.timeID
union all
select yt47.id
, yt47.timeID
, 240 as IndicatorID
, yt47.score/yt48.score as score
from yt47
join yt48
on yt47.id = yt48.id
and yt47.timeID = yt48.timeID
/
This can be easily solved using MODEL clause.
SQL Fiddle
select id, timeid, indicatorid, score
from myt
model return updated rows
partition by (id, timeid)
dimension by (indicatorid)
measures(score)
rules(
score[240] = score[45]/score[46],
score[241] = score[47]/score[48]
);
Results:
| ID | TIMEID | INDICATORID | SCORE |
|----|--------|-------------|--------------------|
| 2 | 111 | 241 | 0.8536585365853658 |
| 2 | 111 | 240 | 2.0833333333333335 |
| 1 | 112 | 241 | 0.9120879120879121 |
| 1 | 112 | 240 | 1.4285714285714286 |
| 2 | 112 | 241 | 0.8536585365853658 |
| 2 | 112 | 240 | 2.0833333333333335 |
| 1 | 111 | 241 | 0.9120879120879121 |
| 1 | 111 | 240 | 1.4285714285714286 |
insert into myt
select id, timeid, indicatorid, score
from myt
model return updated rows
partition by (id, timeid)
dimension by (indicatorid)
measures(score)
rules(
score[240] = score[45]/score[46],
score[241] = score[47]/score[48]
);
Results:
select id, timeid, indicatorid, score
from myt
Results:
| ID | TIMEID | INDICATORID | SCORE |
|----|--------|-------------|--------------------|
| 1 | 111 | 45 | 20 |
| 1 | 111 | 46 | 14 |
| 1 | 111 | 47 | 83 |
| 1 | 111 | 48 | 91 |
| 1 | 111 | 240 | 1.4285714285714286 |
| 1 | 111 | 241 | 0.9120879120879121 |
| 1 | 112 | 45 | 20 |
| 1 | 112 | 46 | 14 |
| 1 | 112 | 47 | 83 |
| 1 | 112 | 48 | 91 |
| 1 | 112 | 240 | 1.4285714285714286 |
| 1 | 112 | 241 | 0.9120879120879121 |
| 2 | 111 | 45 | 25 |
| 2 | 111 | 46 | 12 |
| 2 | 111 | 47 | 70 |
| 2 | 111 | 48 | 82 |
| 2 | 111 | 240 | 2.0833333333333335 |
| 2 | 111 | 241 | 0.8536585365853658 |
| 2 | 112 | 45 | 25 |
| 2 | 112 | 46 | 12 |
| 2 | 112 | 47 | 70 |
| 2 | 112 | 48 | 82 |
| 2 | 112 | 240 | 2.0833333333333335 |
| 2 | 112 | 241 | 0.8536585365853658 |

delete duplicate rows from my table

i need to delete all duplicate rows in my table - but leave only one row
MyTbl
====
Code | ID | Place | Qty | User
========================================
1 | 22 | 44 | 34 | 333
2 | 22 | 44 | 34 | 333
3 | 22 | 55 | 34 | 333
4 | 22 | 44 | 34 | 666
5 | 33 | 77 | 12 | 999
6 | 44 | 11 | 87 | 333
7 | 33 | 77 | 12 | 999
i need to see this:
Code | ID | Place | Qty | User
=======================================
1 | 22 | 44 | 34 | 333
3 | 22 | 55 | 34 | 333
4 | 22 | 44 | 34 | 666
5 | 33 | 77 | 12 | 999
6 | 44 | 11 | 87 | 333
In most databases, the fastest way to do this is:
select distinct t.*
into saved
from mytbl;
delete from mytbl;
insert into mytbl
select *
from saved;
The above syntax should work in Access. Other databases would use truncate table instead of delete.
Try this,
WITH CTEMyTbl (A,duplicateRecCount)
AS
(
SELECT id,ROW_NUMBER() OVER(PARTITION by id,place,qty,us ORDER BY id)
AS duplicateRecCount
FROM MyTbl
)
DELETE FROM CTEMyTbl
WHERE duplicateRecCount > 1

Selecting records from Foreign Key table where multiple items match the condition

I am getting data from a third party in form of below tables in MS Access 2000 file format
Papers and
PaperTags
Below is the sample data from these tables.
Papers table and sample data
+----+----------+
| ID | PaperID |
+----+----------+
| 1 | 658 |
| 2 | 659 |
| 3 | 660 |
| 4 | 661 |
| 5 | 662 |
| 6 | 663 |
| 7 | 664 |
+----+----------+
PaperTags table and sample data
+----+----------+----------------------------------------+
| ID | PaperID | TagID |
+----+----------+----------------------------------------+
| 1 | 663 | 3 |
| 2 | 663 | 15 --Y |
| 3 | 663 | 17 |
| 4 | 663 | 18 --Y |
| 5 | 664 | 14 |
| 62 | 658 | 9 |
| 63 | 658 | 14 |
| 64 | 658 | 17 |
| 65 | 659 | 15 --Y |
| 66 | 659 | 17 |
| 67 | 659 | 18 --Y |
| 68 | 660 | 17 |
| 69 | 660 | 18 --N as it has only 18 and not 15 |
| 70 | 661 | 10 |
| 71 | 661 | 17 |
| 72 | 661 | 18 --N as it has only 18 and not 15 |
| 73 | 662 | 18 --N as it has only 18 and not 15 |
| 74 | 662 | 14 |
| 75 | 662 | 17 |
| 76 | 662 | 18 --N as it has only 18 and not 15 |
+----+----------+----------------------------------------+
Now my end user will pass one or more TagIDs for example 15 and 18 my goal is to find all the PaperIDs which have all of these TagIDs. In these example I need to return 663 and 659
I have tried below query but if there is any glitch in data then it doesn't work. For example PaperID 662 appears twice in the table with the same TagID so count(PaperID) = 2 turns out to be true and it will end up in my result.
select Count(PaperID), PaperID from PaperTags
group by TagID, PaperID
having TagID = 15 or TagID = 18
and count(PaperID) = 2
The other query that I tried is
select * from Papers
where Papers.PaperID
in
(
select PaperTags.PaperID from PaperTags
where (PaperTags.Tagid = 15 or PaperTags.Tagid = 18)
and PaperTags.PaperID = Papers.PaperID
)
I have gone thru below article but as I am using MSAccess I can't use this approach.
Select records from a table where all other records with same foreign key have a certain value
I think there has to be better way to filter. Any help is much appreciated.
Something like this:
SELECT G.ContentID
FROM (
SELECT PT.ContentID, PT.TagID
FROM PaperTags AS PT
WHERE PT.TagID IN (15, 18)
GROUP BY PT.ContentID, PT.TagID
) AS G
GROUP BY G.ContentId
HAVING Count(*) = 2

How to SUM from MySQL for every n record

I have a following result from query:
+---------------+------+------+------+------+------+------+------+-------+
| order_main_id | S36 | S37 | S38 | S39 | S40 | S41 | S42 | total |
+---------------+------+------+------+------+------+------+------+-------+
| 26 | 127 | 247 | 335 | 333 | 223 | 111 | 18 | 1394 |
| 26 | 323 | 606 | 772 | 765 | 573 | 312 | 154 | 3505 |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 |
| 39 | 65 | 86 | 86 | 42 | 21 | NULL | NULL | 300 |
| 39 | 42 | 58 | 58 | 28 | 14 | NULL | NULL | 200 |
| 35 | 11 | 20 | 21 | 18 | 9 | 2 | NULL | 81 |
| 35 | 10 | 25 | 30 | 23 | 12 | 1 | NULL | 101 |
+---------------+------+------+------+------+------+------+------+-------+
I would like to insert a SUM before enter different order_main_id, it would be like this result:
+---------------+------+------+------+------+------+------+------+-------+
| order_main_id | S36 | S37 | S38 | S39 | S40 | S41 | S42 | total |
+---------------+------+------+------+------+------+------+------+-------+
| 26 | 127 | 247 | 335 | 333 | 223 | 111 | 18 | 1394 |
| 26 | 323 | 606 | 772 | 765 | 573 | 312 | 154 | 3505 |
| | 450 | 853 | 1107 | 1098 | 796 | 423 | 172 | 4899 |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 |
| | 50 | 70 | 70 | 70 | 40 | NULL | NULL | 300 |
| 39 | 65 | 86 | 86 | 42 | 21 | NULL | NULL | 300 |
| 39 | 42 | 58 | 58 | 28 | 14 | NULL | NULL | 200 |
| | 107 | 144 | 144 | 70 | 35 | NULL | NULL | 500 |
| 35 | 11 | 20 | 21 | 18 | 9 | 2 | NULL | 81 |
| 35 | 10 | 25 | 30 | 23 | 12 | 1 | NULL | 101 |
| | 21 | 45 | 51 | 41 | 21 | 3 | NULL | 182 |
+---------------+------+------+------+------+------+------+------+-------+
How to make this possible ?
You'll need to write a second Query which makes use of GROUP BY order_main_id.
Something like:
SELECT sum(S41+...) FROM yourTable GROUP BY orderMainId
K
You can actually do this in one query, but with a union all (really two queries, but the result sets are combined to make one awesome result set):
select
order_main_id,
S36,
S37,
S38,
S39,
S40,
S41,
S42,
S36 + S37 + S38 + S39 + S40 + S41 + S42 as total,
'Detail' as rowtype
from
tblA
union all
select
order_main_id,
sum(S36),
sum(S37),
sum(S38),
sum(S39),
sum(S40),
sum(S41),
sum(S42),
sum(S36 + S37 + S38 + S39 + S40 + S41 + S42),
'Summary' as rowtype
from
tblA
group by
order_main_id
order by
order_main_id, RowType
Remember that the order by affects the entirety of the union all, not just the last query. So, your resultset would look like this:
+---------------+------+------+------+------+------+------+------+-------+---------+
| order_main_id | S36 | S37 | S38 | S39 | S40 | S41 | S42 | total | rowtype |
+---------------+------+------+------+------+------+------+------+-------+---------+
| 26 | 127 | 247 | 335 | 333 | 223 | 111 | 18 | 1394 | Detail |
| 26 | 323 | 606 | 772 | 765 | 573 | 312 | 154 | 3505 | Detail |
| 26 | 450 | 853 | 1107 | 1098 | 796 | 423 | 172 | 4899 | Summary |
| 35 | 11 | 20 | 21 | 18 | 9 | 2 | NULL | 81 | Detail |
| 35 | 10 | 25 | 30 | 23 | 12 | 1 | NULL | 101 | Detail |
| 35 | 21 | 45 | 51 | 41 | 21 | 3 | NULL | 182 | Summary |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 | Detail |
| 38 | 25 | 35 | 35 | 35 | 20 | NULL | NULL | 150 | Detail |
| 38 | 50 | 70 | 70 | 70 | 40 | NULL | NULL | 300 | Summary |
| 39 | 65 | 86 | 86 | 42 | 21 | NULL | NULL | 300 | Detail |
| 39 | 42 | 58 | 58 | 28 | 14 | NULL | NULL | 200 | Detail |
| 39 | 107 | 144 | 144 | 70 | 35 | NULL | NULL | 500 | Summary |
+---------------+------+------+------+------+------+------+------+-------+---------+
This way, you know what is and what isn't a detail or summary row, and the order_main_id that it's for. You could always (and probably should) hide this column in your presentation layer.
For things like these I think you should use a reporting library(such as Crystal Reports), it'll save you a lot of trouble, check JasperReports and similar projects on osalt