i have the next three examples of the syntaxis of the conditional IF in the language Octave
1)
if(condition)
body
end
2)
if(condition)
body
else
body-alternative
end
3)
if(condition)
body
elseif(condition)
body
else
body-alternative
end
in the third example there could be as many elseif´s as you want
and i have to create a grammar for these If's. So far i have the next rules
<IF> := if <CONDITION> <BODY> <S>
<S> := end | else <BODY> end | <ELSEIF>
<ELSEIF> := elseif <CONDITION> <BODY> <ELSEIF> | else <BODY> end
but i dont know how to create the rules for the non-terminal CONDITION, any ideas???
<CONDITION> is just an <EXPRESSION> inside of parentheses. (The expression needs to have a boolean value, but that's not a syntactic restriction; any expression is syntactically valid.)
Creating grammars for expressions is tedious and requires a detailed knowledge of the expression syntax (obviously), but they are generally pretty similar, so you should be able to find any number of examples on the internet.
Of course, you can just look at the octave grammar itself. It's written in bison and you can find it in the octave mercurial repository.
By the way, it is not obvious from the documentation which you quote that the following is also a valid Octave if statement:
if ( condition )
body
elseif ( condition )
body-2
end
In other words, an if statement consists of an if clause, any number (including 0) elseif clauses, an optional else clause, and an end. The fact that there is an elseif clause does not imply that the else clause is required. (So it is like just about every other language which has if statements terminated with some kind of end marker.)
You can try
if ( the condition )
body
elseif ( the condition )
body second
else
what you need
end
Related
Could anyone explain how my MySQL regex script would loop infinitely instead of returning true or false?
'^[[:alnum:]]+([_\\.\\-]?[[:alnum:]]+)*#[[:alnum:]]+([_\\.\\-]?[[:alnum:]]+)*(\\.[[:alnum:]]{2,4})+$'
Is there a way to make MySQL return false if it detects an infinite loop?
My entire sql query is:
SELECT
cusworkemail NOT REGEXP '^[[:alnum:]]+([_\\.\\-]?[[:alnum:]]+)*#[[:alnum:]]+([_\\.\\-]?[[:alnum:]]+)*(\\.[[:alnum:]]{2,4})+$' AS invalid_value,
cusworkemail,
num,
cusid_list
FROM (
SELECT
IFNULL(cusworkemail, '') AS cusworkemail,
count(*) AS num,
GROUP_CONCAT(DISTINCT cusid) AS cusid_list
FROM (SELECT cusid, cusworkemail FROM dealCRM.cus WHERE cusworkemail != '' AND cusworkemail IS NOT NULL) AS t
GROUP BY cusworkemail
ORDER BY num DESC
-- LIMIT 0, 10000
) AS c
HAVING invalid_value;
The query will throw an error on regex timeout.
Here is an example of an email that will cause an infinite loop:
"sdasa#kj.nhg " with a space at the end.
Does the parser not detect that it is repeating the same internal state?
The pattern [[:alnum:]]+([_\\.\\-]?[[:alnum:]]+)* is potentially causing a lot of backtracking. It is not an infinite loop, just a lot of looping which will hit a limit.
Take for instance this string which should not match: "abcdefg"
It will first match [[:alnum:]]+ against "abcdefg", then execute ()* zero times and then find that there is no "#". So it backtracks making [[:alnum:]]+ to match one fewer character: "abcdef". The ()* part can now execute once. But it needs to backtrack again. We can summarise this as:
abcdefg()
abcdef(g)
abcde(fg)
abcd(efg)
abc(defg)
ab(cdefg)
a(bcdefg)
None of this divisions of the characters into the first or second [[:alnum:]]+ pattern helps to get past that #. In the example you have given this backtracking will occur at the end so that there is a Cartesian product of backtracking in the part before the # and in the part after it.
Conclusion: you should remove that ?. It is not an optional match. The optional part is already reflected by the surrounding *. Either there is a hyphen/dot/underscore and the pattern in parentheses should be executed, or there is not, and then that pattern should not be executed.
Note you have this pattern twice, so two corrections are needed.
I am trying to create a function that concatenates two strings of text. I cannot simply use the concat function, I have to create a function that I can input two strings of text like String 1 = "Hi my name is' and String 2 = "Gary"
EDITOR'S NOTE: This is homework help. For future readers, these answers may not be applicable outside of given homework guidelines.
EDIT NOTE: In looking back at the original question, it asked for a function. This could be made into a function, but I think a function is way overkill for a fairly simple built-in operation. A user function would be a lot of overhead for something the engine can already easily handle.
In my personal opinion, this is a flawed question from your instructor. The correct answer is to do the very thing you aren't allowed to do. In fact, in MySQL, it's pretty much the only way the engine WANTS you to do that task. However, it can be done.
<teachingMoment>
First, we'll set up simple data.
CREATE TABLE t1 (s1 varchar(50), s2 varchar(50)) ;
INSERT INTO t1 (s1,s2) VALUES ('Hello','World') ;
To do it the way we SHOULD do it:
SELECT concat(s1, ', ', s2, '!') FROM t1 ;
Which gives us: Hello, World!. Easy, peasy.
In most* other flavors of SQL, the double-pipe operator (||) can be used for concatenation.
* : "Most" does not include Microsoft T-SQL. It uses + instead.
SELECT s1 || ',' || s2 || '!' FROM t1 ;
Most of the time gives us Hello, World! again. However, using pipes (||) to concatenate is not turned on by default in MySQL (or MariaDB), meaning we must use concat(). To turn this functionality on, we can do this by:
SET sql_mode = 'PIPES_AS_CONCAT' ;
SELECT s1 || ',' || s2 || '!' FROM t1 ;
And now we're back to giving us Hello, World! without concat().
</teachingMoment>
Again, I think this is a very contrived question that doesn't really provide much useful learning other than how to make yourself do something that MySQL was smart enough to stop you from doing. However, I guess it is useful in teaching you how to do it in other languages (except T-SQL).
Good luck.
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=325e5180aecbf5b632f960e777650a76
From comments, It seems you are using MySQL and you might use below function -
CREATE FUNCTION STR_ADD(STRING_1 VARCHAR2(50)
,STRING_2 VARCHAR2(50))
RETURNS VARCHAR2
BEGIN
DECLARE RES_STRING VARCHAR2(100);
SELECT CONCAT(STRING_1, STRING_2) INTO RES_STRING;
RETURN RES_STRING;
END;
In some cases, we are using IN clause in our filters of SSRS reports. A lots of them are causing issues with the performance by using hundreds of items inside of IN clauses.
such as:
WHERE TableA.School IN (#School)
sometimes, the multi-value parameters are really tricky to handle, you might need to do =Join(Mypara.Value,",") in the RDL and write a SQL function to convert them into a set of SQL data to be able to feed the SQL SP. (especially some older version of SSRS).
FYI: function to use to break a comma deliminator string into record set:
CREATE function [dbo].[fnSpark_BreakUpList] (
#List VARCHAR(MAX)
)
RETURNS #csvlist TABLE (Item VARCHAR(MAX))
AS
BEGIN
DECLARE #Item VARCHAR(MAX)
-- Loop through each item in the comma delimited list
WHILE (LEN(#List) > 0)
BEGIN
IF CHARINDEX(',',#list) > 0
BEGIN
SET #Item = SUBSTRING(#List,1,(CHARINDEX(',', #List)-1))
SET #List = SUBSTRING(#List,(CHARINDEX(',', #List) + DATALENGTH(',')),DATALENGTH(#List))
END
ELSE
BEGIN
SET #Item = #List
SET #List = NULL
END
-- Insert each item into the csvlist table
INSERT into #csvlist (Item) VALUES (#Item)
END
RETURN
END
GO
I will post answers shortly to show how to increase the performance by using CHARINDEX. (So you dont have to anything like above....)
If you are not actually want to retrieve the item from the LONG delimited string, but to only filtering it, CHARINDEX is a better way to go for.
Instead of using IN Clause, you could just use:
WHERE CHARINDEX(','+TableA.School+',',','+#School+',') > 0
NOTE:
1. I pad an extra comma at the end of target string 'TableA.School' to avoid the satuation that if a big string contains a sub string same as the filtering item.
(Such as we have a school called 'AB' and another 'ABC' that we dont want the 'ABC' to be picked up when we are targeting for 'AB'.... )
I pad an extra comma at the end of resources string '#School' to ensure that the single item / the last item (they will end without a comma) to be picked up when we are targeting them.
I pad an extra comma at the begining of target string 'TableA.School' to avoid the satuation that if a big string contains a sub string same as the filtering item.
(Such as we have a school called 'AB' and another 'CAB' that we dont want the 'CAB' to be picked up when we are targeting for 'AB'.... )
Example:
I am using:
WHERE
CHARINDEX(','+CAST(DENTIST4.wStudentYear AS VARCHAR(10))+',',','+#StudentYear+',') > 0
TO replace:
WHERE
DENTIST4.wStudentYear IN (#StudentYear)
for one of the report i was doing, which makes 4000+ pages rendering improved from about 10 mins into under a min for a large database (11 G).
IMPORTANT NOTES:
Please make sure the filter report parameters you are passing into the dataset uses JOIN clause.
=Join(Parameters!MyParameter.Value,",")
Hope this helps....
IMPORTANT: This approach ONLY improves performance if the filter has large set of items, for any filters with small set of items IN clause will do better jobs.
I have a table with some RDF statements inside, like Quads(graph, subject, verb, object) and I find myself doing queries like:
select * from quads where verb = 'rdf:type' and object = 'smtg:Type'
select * from quads where verb = 'rdf:label' and object = 'bla bla'
I would like to express this in a form like
select * from quads where type('smtg:Type')
select * from quads where label('bla bla')
While this seems a "trivial" text substitution, I have no idea of how and if this would be implementable in postgresql, though I sort of expect this to be impossible.
To the best of my knowledge I can use a function to hardcode the constants, and do
select * from quads where rdftype() = verb and object = 'smtg:Type'
or I can use a function as the from argument like
select * from typed('smtg:Type')
sadly, the former is quite verbose, and the latter does not seem to be amendable to combination e.g. I can't do an hypothetical
select * from quads where type('smtg:Type') and inGraph('mygraph')
Is there a way to do what I want? It seems impossible, but I wonder if there is a way.
EDIT: a sqlfiddle instance: http://sqlfiddle.com/#!1/40b2c/3 .
To be more clear, the reason why this seems unfeasible is that the macro-ish function would be returning a boolean (it is used in the where clause, as if it where a select $1=somevalue) but using an "implicit" row argument in which it would access multiple fields at once, and I have not seen such an example in the pg docs.
and the latter [function] does not seem to be amendable to combination e.g. I
can't do an hypothetical
As long as the return type is stable, you can do pretty much anything in a plpgsql function.
You did not disclose how to resolve type('smtg:Type') or inGraph('mygraph') - are these supposed to be functions? Returning .. what?
But for a simple case like this even a plain SQL function should do the job:
CREATE OR REPLACE FUNCTION f_foo (_type text, _graph text DEFAULT NULL)
RETURNS SETOF quads AS
$func$
SELECT *
FROM quads
WHERE CASE WHEN $1 IS NOT NULL THEN ... ELSE ... END
AND CASE WHEN $2 IS NOT NULL THEN ... ELSE ... END
ORDER BY ...;
$func$ LANGUAGE sql;
In PostgreSQL 9.2 or later you can also use parameter names instead of positional parameters ($1, $2, ..) in SQL functions.
Call:
Since I defined a DEFAULT for the second parameter, you can call this function with one or two parameters:
SELECT * FROM f_foo('smtg:Type');
Or:
SELECT * FROM f_foo('smtg:Type', 'mygraph');
According to the MySQL documentation:
As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get
the results you expect, but this is not guaranteed.
http://dev.mysql.com/doc/refman/5.6/en/user-variables.html
However, in the book High Perfomance MySQL there are a couple of examples of using this tactic to improve query performance anyway.
Is the following an anti-pattern and if so is there a better way to write the query while maintaining good performance?
set #last = null;
select tick, count-#last as delta, #last:=count from measurement;
For clarification, my goal is to find the difference between this row and the last. My table has a primary key on tick which is a datetime column.
Update:
After trying Shlomi's suggestion, I have reverted back to my original query. It turns out that using a case statement with aggregate functions produces unexpected behavior. See for example:
case when (#delta := (max(measurement.count) - #lastCount)) AND 0 then null
when (#lastCount := measurement.count) AND 0 then null
else #delta end
It appears that mysql evaluates the expressions that don't contain aggregate functions on a first pass through the results, and then evaluates the aggregate expressions on a second (grouping) pass. It appears to evaluate the case expression during or after that second pass and use the precalculated values from the first pass in that evaluation. The result is that the third line #delta is always the initial value of #delta (because assignment didn't happen until the grouping pass). I attempted to incorporate a group function into the line with #delta but couldn't get it to behave as expected. So I ultimately when back to my original query which didn't have this problem.
I would still love to hear any more suggestions about how to better handle a query like this.
Update 2:
Sorry for the lack of response on this question, I didn't have a chance to investigate further until now.
Using Shlomi's solution it looks like I had a problem because I was using a group by function when I read my #last variable but not when I set it. My code looked something like this:
CASE
WHEN (#delta := count - #last) IS NULL THEN NULL
WHEN (#last:= count ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
MySQL appears to process expressions that don't contain aggregate functions in a first pass and ones that do in a second pass. The strange thing in the code above is that even when cumulative evaluates to true MySQL must see the AVG aggregate function in the ELSE clause and decides to evaluate the whole inner CASE expression in the second pass. Since #delta is set in an expression without an aggregate function it seems to be getting set on the first pass and by the time the second pass happens MySQL is done evaluating the lines that set #delta and #last.
Ultimately I seem to have found a fix by including aggregate functions in the first expressions as well. Something like this:
CASE
WHEN (#delta := max(count) - #last) IS NULL THEN NULL
WHEN (#last:= max(count) ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
My understanding of what MySQL is doing is purely based on testing and conjecture since I didn't read the source code, but hopefully this will help others who might run into similar problems.
I am going to accept Shlomi's answer because it really is a good solution. Just be careful how you use aggregate functions.
I've researched this issue in depth, and wrote a few improvements on the above.
I offer a solution in this post, which uses functions whose order can be expected. Also consider my talk last year.
Constructs such as CASE and functions such as COALESCE have known underlying behavior (at least until this is changed, right?).
For example, a CASE clause inspects the WHEN conditions one by one, by order of definition.
Consider a rewrite of the original query:
select
tick,
CASE
WHEN (#delta := count-#last) IS NULL THEN NULL
WHEN (#last:=count ) IS NULL THEN NULL
ELSE #delta
END AS delta
from
measurement,
(select #last := 0) s_init
;
The CASE clause has three WHEN conditions. It executes them by order until it meets the first that succeeds. I've written them such that the first two will always fail. It therefore executes the first, then turns to execute the second, then finally returns the third. Always.
I thus overcome the problem of expecting order of evaluation, which is a real and true problem, mostly evident when you start adding more complex clauses such as GROUP BY, DISTINCT, ORDER BY and such.
As a final note, my solution differs from yours in the first row on the result set -- with yours' it returns NULL, with mine it returns the delta between 0 and count. Had I used NULL I would have needed to change the WHEN conditions in some other way -- making sure they would fail on NULL values.