Can I do recursion in plain SQL? - DB2 Version 9 - stored-procedures

I'm creating a stored procedure to do something recursively. I want to run something like this:
SELECT DISTINCT POLICY.CONTRACT_ID
FROM POLICY
INNER JOIN LOAN_PART ON POLICY.LOAN_DETAIL_ID=LOAN_PART.LOAN_DETAIL_ID
INNER JOIN APPLICATION_CONTRACTSTUB ON LOAN_PART.LOAN_PART_ID=APPLICATION_CONTRACTSTUB.LOAN_PART_ID
INNER JOIN CONTRACTSTUB ON APPLICATION_CONTRACTSTUB.CONTRACTSTUB_ID=CONTRACTSTUB.CONTRACTSTUB_ID
WHERE CONTRACTSTUB.REF = VARYING_REF
AND CONTRACTSTUB.STUB_ID = VARYING_ID;
It returns a VARCHAR, which I want to parse, in order to get new values for VARYING_ID and VARYING_REF, like this:
SET VARYING_ID = SUBSTR(RETURNED_VARCHAR, 3, 6);
SET VARYING_REF= SUBSTR(RETURNED_VARCHAR, 9, 8);
And recursively repeat until RETURNED_VARCHAR is null (then I will have my required VARYING_ID (I didn't design this DB)).
Now, I know I can do this with a cursor and while/for loop, or a recursive stored procedure. I just want to make sure that I am not being a little bit clumsy in so doing.
SQL has matured over the years and I remember there were some tricks in oracle for looking deep into n-level relationships, for example.
Can anyone recommend anything, or shall I get on with cursors and such things.
**EDIT -- here is some sample data:
CONTRACT_STUB
CONTRACTSTUB_ID POL_REF POL_ID
1 qwerty 12345678
2 asdfgh 78945612
3 bnmxcv 45678912
4 dfghjk 14785236
APPLICATION_CONTRACTSTUB
LOAN_PART_ID CONTRACTSTUB_ID
1 1
2 2
3 3
4 4
LOAN_PART
LOAN_DETAIL_ID LOAN_PART_ID
1 1
2 2
3 3
4 4
POLICY
CONTRACT_ID LOAN_DETAIL_ID
00asdfgh78945612 1
00bnmxcv45678912 2
00dfghjk14785236 3
4
I can't get my image to display...
Note: POLICY.CONTRACT_ID is a concatenation of ('00', VARYING_REF, VARYING_ID) - e.g. 00abcdef12345678, where the VARYING_REF and VARYING_ID represent the parent policy of the related CONTRACTSTUB. Where that value is blank, there is no 'parent'. It is that (orphaned) VARYING_REF and VARYING_ID, that I want. (I will return '00'+VARYING_REF+VARYING_ID)
The combination 'dfghjk' and '14785236' will return itself: 00dfghjk14785236
as will all the other combinations (return 00dfghjk14785236) found in CONTRACT_STUB.
I'm exhausted after that, Hope I haven't messed it up.

I just read something about SQL recursion yesterday. There is a whole chapter about it in the DB2 SQL Cookbook (at least in version 9.5).

Related

Are there only 16 digits in a sum of decimal

create table t (mnt decimal(20,2));
insert into t values (111340534626262);
insert into t values (0.56);
select sum(mnt) from t;
select sum(mnt::decimal(20,2))::decimal(20,2) from t;
I can't get more than 16 digits. Any idea?
Using IDS 12.10FC10.
When I run the code shown in my sqlcmd program, I get the output:
111340534626262.56
111340534626262.56
When I run the code shown in Informix's DB-Access program, I get this output (slightly altered):
(sum)
111340534626263
1 row(s) retrieved.
(expression)
111340534626263
1 row(s) retrieved.
The problem, therefore, is probably in the display mechanism in DB-Access rather than in the server itself.
If you're writing your own code, it is relatively straight-forward to ensure that the display is accurate and complete. Using DB-Access is not necessarily the best way to go.

stack data and restructure without using var to cases or casestovar in SPSS

I have the following situation: a loop (stack data) with only 1 index variable and with multiple items corresponding to the statements, as in the picture below (sorry it is Excel, but is the same as in SPSS):
stack data - cases on multiple lines, but never filling for 1 respondent all the columns
I want to reach to the following situation but without using casestovars to restructure, because that creates a lot of empty variables. I remember for older versions it was a command like Update, which was moving up the cases, to reach the following result:
reducing the cases per respondent
Like starting from this:
ID Index Q1_1 Q1_2 Q1_3 Q1_4 Q1_5 Q1_6
1 1 1 1
1 2 1 1
1 3 1 1
To reach to this:
ID Q1_1 Q1_2 Q1_3 Q1_4 Q1_5 Q1_6
1 1 1 1 1 1 1
But without using casestovars. Is there any command in SPSS syntax for this?
Thank you very much, have a nice day!
Not entirely sure how variable your data structure is likely to be in reality but if as demo'ed where you have only a single response for each q1_1 to q1_6 per respondent ID, then the below would be sufficient:
dataset declare dsAgg.
aggregate outfile="dsAgg" /break=respid /q1_1 to q1_6=max(q1_1 to q1_6).
Also not sure of the significance of duplicate index values within the same respondent IDs, if this was intended or not.
The following syntax could do the job -
* first we'll recreate your example data.
data list list/respid index q1_1 to q1_6.
begin data
1,1,1,,,,,
1,2,,2,,,,
1,3,,,1,,,
1,4,,,,2,,
1,5,,,,,1,
1,6,,,,,,2
2,1,3,,,,,
2,1,,4,,,,
2,2,,,5,,,
2,2,,,,4,,
2,3,,,,,3,
2,3,,,,,,2
end data.
* now to work: first thing is to make sure the data from each ID are together.
sort cases by respid index.
* the loop will fill down the data to the last line of each ID.
do repeat qq=q1_1 to q1_6.
if respid=lag(respid) and missing(qq) qq=lag(qq).
end repeat.
* the following lines will help recognize the last line for each ID and select it.
compute lineNR=$casenum.
aggregate /outfile=* mode=ADDVARIABLES/break=respid/MXlineNR=max(lineNR).
select if lineNR=MXlineNR.
exe.

Auto-assigning objects to users based on priority in Postgres/Ruby on Rails

I'm building a rails app for managing a queue of work items. I have several types of users ("access levels") to whom I want to auto-assign these work items.
The end goal is an "Auto-assign" button on one of my views that will automatically grab the next work item based on a priority, which is defined by the users's access level.
I'm trying to set up a class method in my work_item model to automatically sort work items by type based on the user's access level. I am looking at something like this:
def self.auto_assign_next(access_level)
case
when access_level = 2
where("completed = 'f'").order("requested_time ASC").limit(1)
when access_level > 2
where("completed = 'f'").order("CASE WHEN form='supervisor' THEN 1 WHEN form='installer' THEN 2 WHEN form='repair' THEN 3 WHEN form='mail' THEN 4 WHEN form='hp' THEN 5 ELSE 6 END").limit(1)
end
This isn't very DRY, though. Ideally I'd like the sort order to be configurable by administrators, so maybe setting up a separate table on which the sort order is kept would be best. The problem with that idea is that I have no idea how to pass the priority order on that table to the [postgre]SQL query. I'm new to SQL in general and somewhat lost with this one. Does anybody have any suggestions as to how this should be handled?
One fairly simple approach starts with turning your case statement into a new table, listing form values versus what precedence value they should be sorted by:
id | form | precedence
-----------------------------------
1 | supervisor | 1
2 | installer | 2
(etc)
Create a model for this, say, FormPrecedences (not a great name, but I don't totally grok your data model so pick one that better describes it). Then, your query can look like this (note: I'm assuming your current model is called WorkItems):
when access_level > 2
joins("LEFT JOIN form_precedences ON form_precedences.form = work_items.form")
.where("completed = 'f'")
.order("COALESCE(form_precedences.precedence, 6)")
.limit(1)
The way this works isn't as complicated as it looks. A "left join" in SQL simply takes all the rows of the table on the left (in this case, work_items) and, for each row, finds all the matching rows from the table on the right (form_precedences, where "matching" is defined by the bit after the "ON" keyword: form_precedences.form = work_items.form), and emits one combined row. If no match is found, a LEFT JOIN will still emit a row, but with all the right-hand values being NULL. A normal join would skip any rows with no right-hand match found.
Anyway, with the precedence data joined on to our work items, we can just sort by the precedence value. But, in case no match was found during the join above, that value will be NULL -- so, I use COALESCE (which returns the first of its arguments that's not NULL) to default to a precedence of 6.
Hope that helps!

Return only results based on current object for dynamic menus

If I have an object that has_many - how would I go about getting back only the results that are related to the original results related ids?
Example:
tier_tbl
| id | name
1 low
2 med
3 high
randomdata_tbl
| id | tier_id | name
1 1 xxx
2 1 yyy
3 2 zzz
I would like to build a query that returns only, in the case of the above example, rows 1 and 2 from tier_tbl, because only 1 and 2 exist in the tier_id data.
Im new to activerecord, and without a loop, don't know a good way of doing this. Does rails allow for this kind of query building in an easier way?
The reasoning behind this is so that I can list only menu items that relate to the specific object I am dealing with. If the object i am dealing with has only the items contained in randomdata_tbl, there is no reason to display the 3rd tier name. So i'd like to omit it completely. I need to go this direction because of the way the models are set up. The example im dealing with is slightly more complicated.
Thanks
Lets call your first table tiers and second table randoms
If tier has many randoms and you want to find all tiers whoes id present in table randoms, you can do it that way:
# database query only
Tier.joins(:randoms).uniq
or
# with some ruby code
Tier.select{ |t| t.randoms.any? }

Return every nth row from database using ActiveRecord in rails

Ruby 1.9.2 / rails 3.1 / deploy onto heroku --> posgresql
Hi, Once a number of rows relating to an object goes over a certain amount, I wish to pull back every nth row instead. It's simply because the rows are used (in part) to display data for graphing, so once the number of rows returned goes above say 20, it's good to return every second one, and so forth.
This question seemed to point in the right direction:
ActiveRecord Find - Skipping Records or Getting Every Nth Record
Doing a mod on row number makes sense, but using basically:
#widgetstats = self.widgetstats.find(:all,:conditions => 'MOD(ROW_NUMBER(),3) = 0 ')
doesn't work, it returns an error:
PGError: ERROR: window function call requires an OVER clause
And any attempt to solve that with e.g. basing my OVER clause syntax on things I see in the answer on this question:
Row numbering in PostgreSQL
ends in syntax errors and I can't get a result.
Am I missing a more obvious way of efficiently returning every nth task or if I'm on the right track any pointers on the way to go? Obviously returning all the data and fixing it in rails afterwards is possible, but terribly inefficient.
Thank you!
I think you are looking for a query like this one:
SELECT * FROM (SELECT widgetstats.*, row_number() OVER () AS rownum FROM widgetstats ORDER BY id) stats WHERE mod(rownum,3) = 0
This is difficult to build using ActiveRecord, so you might be forced to do something like:
#widgetstats = self.widgetstats.find_by_sql(
%{
SELECT * FROM
(
SELECT widgetstats.*, row_number() OVER () AS rownum FROM widgetstats ORDER BY id
) AS stats
WHERE mod(rownum,3) = 0
}
)
You'll obviously want to change the ordering used and add any WHERE clauses or other modifications to suit your needs.
Were I to solve this, I would either just write the SQL myself, like the SQL that you linked to. You can do this with
my_model.connection.execute('...')
or just get the id numbers and find by id
ids = (1..30).step(2)
my_model.where(id => ids)

Resources