Laravel query builder `SELECT (x IN (?)) AS y` - laravel

How do I make this kind of SELECT with Laravel's query builder:
SELECT *, (sector1 IN (...)) AS s1, (sector2 IN (...)) AS s2, (sector3 IN (...)) AS s3
FROM jobs
WHERE (sector1 IN (1, 2) OR sector3 IN (1, 2) OR sector3 IN (1, 2))
ORDER BY (s1 AND s2 AND s3) DESC, (s1 AND s2) DESC, (s1 AND s3) DESC, etc...
The WHERE part is easy with whereIn(), and the ORDER part is easy with orderByRaw(), but how do I make the SELECT?
The results s1, s2 and s3 can now be used for sorting: first if all 3 sectors match, than if sectors 1 and 2 match, than if sectors 1 and 3 match, etc.
The (...) are 1 or more sectors from user input. They must be escaped and inserted etc, like a WHERE sector1 IN (...) would.
But how?
selectRaw only helps a little, because it doesn't expand an array into multiple placeholders. This is what I have now, but that can't be it:
$query->selectRaw("sector1 IN (" . implode(',', array_fill(0, count($filters['sectors']), '?')) . ") AS s1", $filters['sectors']);
I have to expand the placeholders myself? There must be a way to let the query builder do that. Maybe an ConditionExpression I can't find? The builder itself doesn't seem to have a way to expand ?, only the Grammar does that when executing the query, which is why whereIn/whereNotIn etc are all explicit methods.

whereIn() internally uses Grammar::parameterize() to expand the placeholders.
You can also use it separately:
$grammar = new \Illuminate\Database\Query\Grammars\MySqlGrammar();
$query->selectRaw("sector1 IN (" . $grammar->parameterize($filters['sectors']) . ") AS s1", $filters['sectors']);

Related

SPARQL filter and union

I am trying to list all entries whose names start with the letter 'R' and are older than 20 but It is not working - Can you please give me a hint ?
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?givenname ?Age ?firstName
WHERE {
?Person foaf:givenname ?firstName
{FILTER (?Age > '20')}
UNION
{FILTER regex(?givename, "^(R)")}
}
To find names that start with "R", you can use STRSTARTS():
FILTER( STRSTARTS(?givename, "R") ) .
To filter based on the age, you first have to add/bind this variable in a triple pattern, e.g.:
?Person ex:yourAgeProperty ?Age .
Your age FILTER compares strings (as you use quotation marks and don’t specify a datatype, which defaults to xsd:string). In case the age is given as xsd:integer in your data, you could use:
FILTER( ?Age > "20"^^xsd:integer ) .
And if both filters need to apply, simply list them one after the other (without {} and without UNION). Or you could combine them:
FILTER( STRSTARTS(?givename, "R") && ?Age > "20"^^xsd:integer ) .

How create a siddhi app with Multiple conditional count

I have a special situation and I can not implement it with siddhi options like window, pattern or aggregation functions. The data comes from 2 streams, I set the source in both streams of KAFKA and I set the list of topics in siddhi source p1, p2. I wrote a query for checks 2 rules (type = "h") and (type = "g"). The siddhi app must only allows events to match these conditions. I need to aggregate every 10 seconds, when the number of events that match the first condition is 2 and the number of events that match the second condition is 5 at this time. How?
Finally found the solution:
from stream1#window.time(10 seconds)
select type, id, sum(ifThenElse(type == 'h', 1, 0)) as cnt1, sum(ifThenElse(type == 'g', 1, 0)) as cnt2
having cnt1 == 2 and cnt2 == 5
insert all events into stream2;
I tested this code manytimes with many values(0, 1, 2, ...) that passed all of them.

Add a computed field in a select using Eloquent

I would like to add a computed field in my select result using Eloquent.
$dbEntry->query->select('id', '(s1 + s2) as scoreSum')->toSql();
// "select `id`, `(s1` as `s2)` from `mytable`"
I would expect:
// "select `id`, `s1` + `s2` as scoreSum from `mytable`"
Context: in my real world stuff, what I am computing is an haversine formula (on a limited set of entries).
You need to use a raw query instead, e.g. like this:
->select(DB::raw('id, (s1 + s2) as scoreSum'))
Make sure you import the DB as well.

Can this Aggregate Lambda expression be converted to a LINQ query?

I have a list of integers summed by an Aggregate method using a Lambda expression:
var mylist = new int[] { 3, 4, 5 };
var result = mylist.Aggregate((a, b) => a + b);
As I understand it, a Lambda expression can always be converted to a LINQ query. How would such a LINQ query look for my example?
EDIT: I understand .Sum may be better to add the numbers in my example. But I would really like to know how this Aggregate will look with a LINQ Query instead.
It already IS a LINQ query, Aggregate is a LINQ operator, i'm assuming what you meant was how it would look like in the LINQ comprehension syntax? The comprehension syntax only has a few built in features (select , where, multiple selects, groupby etc), it doesn't have all operators built in so when you need one of those (such as aggregate) you wrap it around parenthèses and keep going with the regular syntax. Since there is nothing there except aggregate it's not possible to give an example so i'll go from a different query:
var mylist = new int[] { 3, 4, 5, 6, 7, 8 };
var result = mylist
.Where(item=>item %2 == 0)
.Aggregate((a, b) => a + b);
var ComprehensiveResult =
(from item in mylist
where item % 2 == 0
select item)
.Aggregate((a, b) => a + b);
Comprehensive syntax is more of a "LINQ for people coming from SQL introduction", there's nothing you can do in it that you can't do with plain using the operators but the reverse isn't true as not all operators have built in replacements. The only thing that comes to mind where Comprehensive syntax is better (aside from personal taste) is multiple selects to generate a cartesian product which is much harder to maintain in plain method syntax.
In this case Aggregate function adds numbers each other. So, the equivalent function is SUM:
var qry = mylist.Sum(x=>x);
or
var qry = (from n in mylist select n).Sum();
[EDIT]
OP has added extra information to the question without informing me about that.
Yes, it's possible to "convert" Aggregate function into linq query, but extension method is needed. See this article: Cumulating values with LINQ

Flatten tuple like a bag

My dataset looks like the following:
( A, (1,2) )
( B, (2,9) )
I would like to "flatten" the tuples in Pig, basically repeating each record for each value found in the inner-tuple, such that the expected output is:
( A, 1 )
( A, 2 )
( B, 2 )
( B, 9 )
I know this is possible when the tuples (1,2) and (2,9) are bags instead.
Your insight is good; it's possible by transforming the tuple in a bag. The schema we want to aim for is: {a: chararray,{(chararray)}} for example: (A,{(1),(2)})
Here is the solution to your problem:
A = LOAD 'data.txt' AS (a:chararray,b:(b1:chararray,b2:chararray));
B = FOREACH A GENERATE a, TOBAG(b.b1,b.b2);
C = FOREACH B GENERATE a, FLATTEN($1);
The magic part is the TOBAG operator.
You can use DataFu's UDF TransposeTupleToBag (http://datafu.incubator.apache.org/docs/datafu/1.1.0/datafu/pig/util/TransposeTupleToBag.html) and then flatten the bag to get a row per item in the bag.
I know this is an old thread but I could not get the above method to work. Thought I will share my findings.
input: (1-2-3, abc)
(4-5-6, xyz)
desired output:
(1, abc)
(2, abc)
(3, abc)
(4, xyz)
(5, xyz)
(6, xyz)
Initially, I used STRSPLIT that generates a tuple resulting in the similar input as above but was unsuccessful.
output = FOREACH input GENERATE FLATTEN(TOBAG(STRSPLIT($0, '-'))), $1
This resulted in the output as:
(1,2,3,abc)
(4,5,6,xyz)
However, when I used tokenize and replace functions I got the desired output.
output = FOREACH input GENERATE FLATTEN(TOKENIZE(REPLACE($0,'-', ' '))), $1;

Resources