Writing a nested 4gl query after 'WHERE' - progress-4gl

I only have access to write a 4gl query after Where(. Is it possible to write a nested query to search in a completely different table?
For example
**FOR EACH WORK_ORDER WHERE(**
//my query starts on this line
1=1 and
( for each purchase_order where key <> '123' end)
This obviously does not work, but is it possible to make it work?
This query will give me ERROR: PREPARE syntax is {FOR|PRESELECT} EACH OF..WHERE" (7324)

No, it's not possible. The query needs to be aware of all it's buffers. If the only thing you can manipulate is the actual WHERE-clause it won't be enough.
This is how it can be done, but you need to manipulate more than just the where:
DEFINE QUERY q1 FOR WORK_ORDER, PURCHASE_ORDER.
QUERY q1:QUERY-PREPARE("FOR EACH WORK_ORDER, EACH PURCHASE_ORDER WHERE PURCHASE_ORDER.id = WORK_ORDER.id" ).
QUERY q1:QUERY-OPEN().
QUERY q1:GET-FIRST.
IF AVAILABLE work_order THEN DO:
DISP work_order.
END.
ELSE DO:
DISP "no work_order".
END.
IF AVAILABLE purchase_order THEN DO:
DISP purchase_order.
END.
ELSE DO:
DISP "no purchase_order".
END.
QUERY q1:QUERY-CLOSE.

You could try using a join.
FOR EACH WORK_ORDER NO-LOCK WHERE... , EACH PURCHASE_ORDER WHERE PURCHASE_ORDER.key <> '123'

Related

postgres case statement with subquery

I have a subquery like this
with subquery as (select host from table_A where << some condition >>)
and in my main query, I am querying data from another table called table_B, and one of the columns is called destination_host. Now I need to check if the destination_host is in the list returned from my subquery, then I want to output TypeA in my select statement or else TypeB. My select statement looks something like
select name, place, destination_host
from table_B
where <<some condition>>
I want to output a fourth column that is based on a condition check, let's say we call this host_category and if the destination_host value exists in the subquery then I want to add value typeA or else typeB. Please can you help me understand how to write this. I understand that it is hard to provide guidance if you don't have actual data to work with.
I tried using case statements such as this one:
when (destination_host in (select host from subquery)) THEN 'typeA'
when (destination_host not in (select host from subquery)) THEN 'typeB'
end as host_category
but I don't think this is the way to solve this problem.
I would use EXISTS:
WITH subquery AS (...)
SELECT CASE WHEN EXISTS (SELECT 1 FROM subquery
WHERE subquery.host = table_b.destination_host)
THEN 'typeA'
ELSE 'typeB'
END
FROM table_b;
With queries like that, you have to take care of NULL values. If table_b.destination_host is NULL, the row will always show up as typeB, because NULL = NULL is not TRUE in SQL.

REDSHIFT if value in list

I am trying to set some variables on the top of my query via CTEs to make maintenance of a long query more easy to handle.
I have extracted an example of what I am trying to achieve. I am not managing to make 'tags' be perceived as a list rather than a whole string. I have tried split_part but have not managed to get what I require.
WITH tmp AS (
SELECT
'tag1, tag2, tag3' as tags
)
select
CASE WHEN 'tag1' in (select tags from tmp) THEN 1 ELSE 0 END matched_tags
Basically what I need is to have a string 'tag1' and see if it exists in the list 'tag1','tag2' or 'tag3'. This should give me 1 as there is a match
This is obviously not working because it is taking the 'tag1, tag2, tag3' as one string so there is no match.
Can anyone help me with this?
The STRPOS() function should do what you want. https://docs.aws.amazon.com/redshift/latest/dg/r_STRPOS.html
Something like this:
WITH tmp AS (
SELECT
'tag1, tag2, tag3' as tags
)
SELECT
CASE WHEN STRPOS(tags, 'tag1') > 0 THEN 1 ELSE 0 END as matched_tags
FROM tmp;

Get results from HQL query with the same order as given list

I'm trying make a query with HQL that will stay with the same order as given list of IDs. I know it's possible with SQL but I can't find any way to do it with HQL (and I cannot do it with native SQL because I got many joins)
Example
fingerIds = [3,1,10,4]
SELECT p FROM People p
JOIN FETCH p.fingers f
WHERE f.id IN :fingerIds
DB: PostgreSQL 10.4
Hibernate: 4.3.11.Final
Eg. Given list of IDs: [3,1,10,4]
Actual result's order: [1,3,4,10]
Expected result's order: [3,1,10,4]
You can obtain the order by adding to your query the keyword FIELD, in your example:
SELECT p FROM People p
JOIN FETCH p.fingers f
WHERE f.id IN :fingerIds
ORDER BY FIELD(f.ID,3,1,10,4)
Ofc you can replace the numbers with your variable :fingerIds
You can find more about that command here.
Returns the index (position) of str in the str1, str2, str3, ... list. Returns 0 if str is not found.

EXISTS in filter returning too many values

I need to write a query that uses EXISTS, rather than IN, so that it will run fast. The filter is being fed so many parameter values that EXISTS seems like the only option. The difference is between a 20+ minute query and a 5 second query.
This is the query I have:
SELECT DISTINCT d.GROUP_NAME
FROM [EMPLOYEE] e JOIN [DATA_FACT] d ON (e.KEY = d.KEY)
WHERE d.DATE BETWEEN #Start and #End
AND EXISTS
(
select '1234567' -- #ID
)
AND e.Location IN (#Location)
ORDER BY d.GROUP_NAME ASC
The problem is that it is returning too many records. Based on the values I'm passing to filter on, I should get 1 row back but instead I am getting 28.
If I remove the EXISTS and add the following then I get the 1 record I need:
AND e.ID IN ('1234567')
Is there a way to fix the query to work with EXISTS so that I get the correct results?
This is essentially what you want if you are going to try to use exists to filter your data_fact table by parameters in your employee table. Not sure how much it's going to improve your performance though when you throw a massive number of employee IDs at it.
SELECT
d.GROUP_NAME
FROM [DATA_FACT] AS d
WHERE d.DATE BETWEEN #Start and #End
AND EXISTS
(
select 1
from EMPLOYEE AS e
WHERE d.[KEY] = e.[KEY]
AND e.[Location] IN (#Location)
AND e.ID IN ('1234567')
)
ORDER BY d.GROUP_NAME ASC

How to get only specific rows on DB, when date range fits SQL condition on a 'tsrange' datatype? [duplicate]

I have this query:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', some_id)
I get the following error:
TypeError: 'int' object does not support indexing
some_id is an int but I'd like to select indicators that have some_id = 1 (or whatever # I decide to put in the variable).
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', [some_id])
This turns the some_id parameter into a list, which is indexable. Assuming your method works like i think it does, this should work.
The error is happening because somewhere in that method, it is probably trying to iterate over that input, or index directly into it. Possibly like this: some_id[0]
By making it a list (or iterable), you allow it to index into the first element like that.
You could also make it into a tuple by doing this: (some_id,) which has the advantage of being immutable.
You should pass query parameters to execute() as a tuple (an iterable, strictly speaking), (some_id,) instead of some_id:
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id,))
Your id needs to be some sort of iterable for mogrify to understand the input, here's the relevant quote from the frequently asked questions documentation:
>>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct
This should work:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id, ))
Slightly similar error when using Django:
TypeError: 'RelatedManager' object does not support indexing
This doesn't work
mystery_obj[0].id
This works:
mystery_obj.all()[0].id
Basically, the error reads Some type xyz doesn't have an __ iter __ or __next__ or next function, so it's not next(), or itsnot[indexable], or iter(itsnot), in this case the arguments to cursor.execute would need to implement iteration, most commonly a List, Tuple, or less commonly an Array, or some custom iterator implementation.
In this specific case the error happens when the classic string interpolation goes to fill the %s, %d, %b string formatters.
Related:
How to implement __iter__(self) for a container object (Python)
Pass parameter into a list, which is indexable.
cur.execute("select * from tableA where id =%s",[parameter])
I had the same problem and it worked when I used normal formatting.
cursor.execute(f'
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" ={some_id};')
Typecasting some_id to string also works.
cursor.execute(""" SELECT * FROM posts WHERE id = %s """, (str(id), ))