How can I use indexed variable in a Firebird stored procedure? I mean, I have output parameters ODATE1, ODATE2, ODATE3, can I use as ':ODATE' || COUNTER to set the value in a loop?
I have 2 tables like this:
1. T_EMPLOYEE
---------------
| ID_E | NAME |
---------------
| 1 | Anne |
---------------
| 2 | Bob |
---------------
2. T_WORK
----------------------------
| ID_W | DATE_W | ID_E |
----------------------------
| 1 | 2021-01-01 | 1 |
----------------------------
| 2 | 2021-01-01 | 2 |
----------------------------
| 3 | 2021-01-02 | 1 |
----------------------------
| 4 | 2021-01-03 | 2 |
----------------------------
From that table I want to make a stored procedure to get this result:
DASHBOARD
-----------------------------------------------------------
| OID_E | ONAME | ODATE1 | ODATE2 | ODATE3 |
----------------------------------------------------------
| 1 | Anne | 1 | 1 | 0 |
-----------------------------------------------------------
| 2 | Bob | 1 | 0 | 1 |
-----------------------------------------------------------
I tried using EXECUTE STATEMENT like this in stored procedure:
DECLARE VARIABLE COUNTER INT;
BEGIN
FOR
SELECT ID_E, NAME FROM T_EMPLOYEE
INTO :OID_E, :ONAME
D0
BEGIN
COUNTER = 1;
WHILE (COUNTER<=3) DO
BEGIN
EXECUTE STATEMENT 'SELECT COUNT(*) FROM T_WORK WHERE DATE_W = ''2021-01-0' || COUNTER ||
''' AND ID_E = ' || :OID_E || ' INTO :ODATE' || COUNTER;
COUNTER = COUNTER + 1;
END
SUSPEND;
END
END /*procedure*/
The procedure can't be compiled.
Then I tried the simple one like this without COUNTER index replacement:
DECLARE VARIABLE COUNTER INT;
BEGIN
FOR
SELECT ID_E, NAME FROM T_EMPLOYEE
INTO :OID_E, :ONAME
D0
BEGIN
COUNTER = 1;
WHILE (COUNTER<=3) DO
BEGIN
EXECUTE STATEMENT 'SELECT COUNT(*) FROM T_WORK WHERE ID_E = :OID_E ' ||
' AND DATE_W =''2021-01-02'' INTO :ODATE2';
COUNTER = COUNTER + 1;
END
SUSPEND;
END
END /*procedure*/
The procedure can be compiled, but when I execute, it will raise this error:
SQL Error: Dynamic SQL Error SQL error code = #1 Token unknown - line #1, column #2 #1. Error Code: -104. Invalid token
Please give me insight. How to use EXECUTE STATEMENT to make a flexible looping to set indexed variable.
Or you have another solution for my needs.
Additional information: Firebird v2.5
You cannot dynamically reference PSQL variables (including parameters) like this. However, you don't need to jump through all these hoops to get the desired results.
You can use something like the following(which doesn't even need a procedure):
select e.ID_E as OID_E, e.NAME as ONAME,
count(case when w.DATE_W = date '2021-01-01' then 1 end) as ODATE1,
count(case when w.DATE_W = date '2021-01-02' then 1 end) as ODATE2,
count(case when w.DATE_W = date '2021-01-03' then 1 end) as ODATE3
from T_EMPLOYEE e
inner join T_WORK w
on w.ID_E = e.ID_E
group by e.ID_E, e.NAME
order by e.ID_E
Fiddle: https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=59066afc0fd7f6b5cb87eac99164e899
I am trying to query solely the IDs of clients that meet specific criteria from a source tab to an output tab and fill 2 columns with static values and 2 columns with dynamic values, based on criteria.
In the source tab I have:
+-----------------------+------+
| Status | ID |
+-----------------------+------+
| Retired/Deceased | 2a33 |
+-----------------------+------+
| Liquidation | 1sTR |
+-----------------------+------+
| Dissolved | 3B76 |
+-----------------------+------+
| Released from company | 463z |
+-----------------------+------+
| Active | 557g |
+-----------------------+------+
| In progress | zz34 |
+-----------------------+------+
| Demo | cc56 |
+-----------------------+------+
Please note, that there are 7 criteria values and I need the output for only 4 of them. Meaning that I need 4 values, based on which there will be binary fill of dynamic columns. The other 3 values are obsolete.
From these 4 values, if I have eg. Criteria 1, then I will have one fill of the 2 dynamic columns, if not (for the other 3 values) I will have other fill values.
So I guess simply going with a binary solution for the selection of the specific values is not applicable.
In the output tab logic:
+--------------------------------------------------------------------------------+
| Output tab |
+--------------------------------------------------------------------------------+
| ID | Status | Reason | Comment | Detail |
+----+--------+--------+----------------------------+----------------------------+
| A1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| B1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| C1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, else | then value 1, |
| | | | criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| D1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| E1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| F1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
| G1 | Static | Static | If criteria = criteria 1, | If criteria = criteria 1, |
| | | | then null, | then value 1, |
| | | | else criteria value | else value 2 |
+----+--------+--------+----------------------------+----------------------------+
Dummy output tab:
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
| Status | ID | Status | Reason | Comment | Detail |
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
| Retired/Deceased | 2a33 | Unable to proceed | Unspecified | Retired/Deceased | Retired/No longer in business |
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
| Liquidation | 1sTR | Unable to proceed | Unspecified | Liquidation | Retired/No longer in business |
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
| Dissolved | 3B76 | Unable to proceed | Unspecified | Dissolved | Retired/No longer in business |
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
| Released from company | 463z | Unable to proceed | Unspecified | (null) | No longer works for the company |
+-----------------------+------+-------------------+-------------+------------------+---------------------------------+
The column 'Status' is not required. I added it just for reference and readability.
Apologies, but I have corporate security restrictions for sharing links to Google Sheets.
The part that I struggle most with is that in column 4 (the first one from the dynamic ones) needs to return the value of the criteria from column 2 from the source tab.
So far I have worked my way around the first part of the query, where I QUERY the IDs based on multiple criteria, labelled and filled the static values columns.
=QUERY(Data!$A$3:$BN,
"SELECT B, 'Unable to proceed', 'Unspecified'
WHERE A = 'Retired/Deceased'
OR A = ''Liquidation'
OR A = 'Dissolved'
OR A = 'Released from company'
AND A IS NOT NULL
LABEL 'Unable to proceed' 'Unspecified' , 'Status' 'Reason'", 1)
However, I am struggling with the dynamic columns, based on multiple criteria.
I looked up ARRAYFORMULA with IFERROR and VLOOKUP in a nested QUERY, but was not able to work my way around it.
Also, I am quite interested in how this would work if there were more than 2 options of values to fill columns 3 and 4 in the output tab.
As far as I know, the way to work around 2 values based on criteria is to nest an IFERROR function to make it binary. But what if there were more than 2 values to fill the arrays with?
based on status:
=QUERY({QUERY(Data!$A$1:$B,
"SELECT B, 'Unable to proceed', 'Unspecified'
WHERE A = 'Retired/Deceased'
OR A = 'Liquidation'
OR A = 'Dissolved'
OR A = 'Released from company'
AND A IS NOT NULL
LABEL 'Unable to proceed''Status', 'Unspecified''Reason'", 1),
QUERY(ARRAYFORMULA(IFERROR(VLOOKUP(
QUERY(Data!$A$2:$B,
"SELECT A
WHERE A = 'Retired/Deceased'
OR A = 'Liquidation'
OR A = 'Dissolved'
OR A = 'Released from company'
AND A IS NOT NULL", 0),
{"Retired/Deceased", "Retired/Deceased", "Retired/No longer in business";
"Liquidation", "Liquidation", "Retired/No longer in business";
"Dissolved", "Dissolved", "Retired/No longer in business";
"Released from company", "", "No longer works for the company"}, {2, 3}, 0), )),
"LABEL Col1 'Comment', Col2 'Detail'", 0)}, , 0)
based on ID:
=QUERY({QUERY(Data!$A$1:$B,
"SELECT B, 'Unable to proceed', 'Unspecified'
WHERE A = 'Retired/Deceased'
OR A = 'Liquidation'
OR A = 'Dissolved'
OR A = 'Released from company'
AND A IS NOT NULL
LABEL 'Unable to proceed''Status', 'Unspecified''Reason'", 1),
QUERY(ARRAYFORMULA(IFERROR(VLOOKUP(
QUERY(Data!$A$2:$B,
"SELECT B
WHERE A = 'Retired/Deceased'
OR A = 'Liquidation'
OR A = 'Dissolved'
OR A = 'Released from company'
AND A IS NOT NULL", 0),
{"2a33", "Retired/Deceased", "Retired/No longer in business";
"1sTR", "Liquidation", "Retired/No longer in business";
"3B76", "Dissolved", "Retired/No longer in business";
"463z", "", "No longer works for the company"}, {2, 3}, 0), )),
"LABEL Col1'Comment', Col2'Detail'", 0)}, , 0)
Suppose I have a simple sheet like
|| A | B | C | D | E | F | G
==============================
1 || 1 | 0 | | ? | 1 | 0 | 1
I want to create a new row where each value is either 1 or 0. The logic is if the cell is either blank or ? then it should be 0.
The closest I got was
=ArrayFormula(if(A1:G1="?", 0, A1:G1))
which gave me
|| A | B | C | D | E | F | G
==============================
1 || 1 | 0 | | ? | 1 | 0 | 1
2 || 1 | 0 | | 0 | 1 | 0 | 1
But as soon as I add an OR for checking blanks with
=ArrayFormula(if(or(A1:G1="?", isblank(A1:G1)), 0, A1:G1))
then I only get 1 cell:
|| A | B | C | D | E | F | G
==============================
1 || 1 | 0 | | ? | 1 | 0 | 1
2 || 1 | | | | | |
What am I doing wrong? Or is there a better way to do this?
Two ways:
Simply place the other condition in the value_is_false location
=ArrayFormula(if(A1:G1="?", 0, IF(ISBLANK(A1:G1), 0, A1:G1)))
Use + to represent OR. This works because "true" values are evaluated to 1 and "false" values are evaluated to 0. So, 0+0=false, 1+0=true. For AND, you multiply...0*0=false, 1*0=false, 1*1=true.
=ArrayFormula(if((A1:G1="?")+(ISBLANK(A1:G1)), 0, A1:G1))
match (p:Product {id:'5116003'})-[r]->(o:Attributes|ExtraAttribute) return p, o
How to match two possible node labels in such a query?
Per cybersam's suggestion, I changed to the follwoing:
MATCH (p:Product {id:'5116003'})-[r]->(o)
WHERE o:Attributes OR o:ExtraAttributes
**WHERE any(key in keys(o) WHERE toLower(key) contains 'weight')**
return o
Now I need to add the 2nd 'where' clause. How to modify that?
You can try using any() function:
match (p:Product {id:'5116003'})-[r]->(o)
where any (label in labels(o) where label in ['Attributes', 'ExtraAttribute'])
return p, o
Also, if you have APOC procedures, you can use apoc.path.expand path expander procedure that expands from start node following the given relationships from min to max-level adhering to the label filters.
match (p:Product {id:'5116003'})
call apoc.path.expand(p, null,"+Attributes|ExtraAttribute",0,1) yield path
with nodes(path) as nodes
// return p and o nodes
return nodes[0], nodes[1]
See more here.
These two single-label forms of your query:
MATCH (p:Product {id:'5116003'})-->(o:Attributes) RETURN p, o;
MATCH (p:Product {id:'5116003'})-->(o) WHERE o:Attributes RETURN p, o;
produce the same execution plan, as follows (I assume that there is an index on :Product(id)):
+-----------------+----------------+------+---------+------------------+--------------+
| Operator | Estimated Rows | Rows | DB Hits | Variables | Other |
+-----------------+----------------+------+---------+------------------+--------------+
| +ProduceResults | 0 | 0 | 0 | o, p | p, o |
| | +----------------+------+---------+------------------+--------------+
| +Filter | 0 | 0 | 0 | anon[33], o, p | o:Attributes |
| | +----------------+------+---------+------------------+--------------+
| +Expand(All) | 0 | 0 | 0 | anon[33], o -- p | (p)-->(o) |
| | +----------------+------+---------+------------------+--------------+
| +NodeIndexSeek | 0 | 0 | 1 | p | :Product(id) |
+-----------------+----------------+------+---------+------------------+--------------+
This two-label form of the second query above:
MATCH (p:Product {id:'5116003'})-->(o) WHERE o:Attributes OR o: ExtraAttribute RETURN p, o;
produces an execution plan that is very similar (and therefore probably not much more expensive):
+-----------------+----------------+------+---------+------------------+-------------------------------------+
| Operator | Estimated Rows | Rows | DB Hits | Variables | Other |
+-----------------+----------------+------+---------+------------------+-------------------------------------+
| +ProduceResults | 0 | 0 | 0 | o, p | p, o |
| | +----------------+------+---------+------------------+-------------------------------------+
| +Filter | 0 | 0 | 0 | anon[33], o, p | Ors(o:Attributes, o:ExtraAttribute) |
| | +----------------+------+---------+------------------+-------------------------------------+
| +Expand(All) | 0 | 0 | 0 | anon[33], o -- p | (p)-->(o) |
| | +----------------+------+---------+------------------+-------------------------------------+
| +NodeIndexSeek | 0 | 0 | 1 | p | :Product(id) |
+-----------------+----------------+------+---------+------------------+-------------------------------------+
By the way, the first query in the answer by #BrunoPeres has a similar execution plan as well, but the Filter operation is very different. It is not clear which would be faster.
[UPDATE]
To answer your updated question: since you cannot have 2 back-to-back WHERE clauses, you can just add more terms to the already existing WHERE clause, like so:
MATCH (p:Product {id:'5116003'})-[r]->(o)
WHERE
(o:Attributes OR o:ExtraAttributes) AND
ANY(key in KEYS(o) WHERE TOLOWER(key) CONTAINS 'weight')
RETURN o;
While implementing a Java regular expression for URL based on the URL BNF published by W3C, I've failed to understand the search part. As quoted:
httpaddress h t t p : / / hostport [ / path ] [ ?
search ]
search xalphas [ + search ]
xalphas xalpha [ xalphas ]
xalpha alpha | digit | safe | extra | escape
alpha a | b | c | d | e | f | g | h | i | j | k |
l | m | n | o | p | q | r | s | t | u | v |
w | x | y | z | A | B | C | D | E | F | G |
H | I | J | K | L | M | N | O | P | Q | R |
digit 0 |1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
safe $ | - | _ | # | . | & | + | -
extra ! | * | " | ' | ( | ) | ,
Search claims it is xalphas seperated by a plus sign.
xalphas can contain plus signs by it self, as claimed by safe.
Thus according to my understanding , it should be:
search xalphas
Where am I wrong here?
That's pretty clearly a mistake (+ is a reserved delimiter for URIs), but the BNF you're linking to seems to be out of date. Probably best to use the one included at the end of the latest RFC 3986.