Does Drill support FILTER WHERE? - apache-drill

Consider following query:
SELECT
COUNT(*) unfiltered,
COUNT(*) FILTER (WHERE a."Id" <= 5) AS filtered
FROM db.example."Articles" a
This should return something like:
unfiltered | filtered
456 | 5
But Apache Drill returns:
unfiltered | filtered
456 | 456
 Apparently FILTER WHERE does not work. Is it bug or feature? If it's not supported, why Drill does not throw any error when parsing this SQL?
Using Drill 1.16.0

Thanks for pointing out this issue. Yes, we don't support this and we should at least throw an exception instead of returning the wrong result. I have created a Jira ticket for this issue: DRILL-7421

Related

HAVING statement on a GROUP_CONCAT field returns no result while the condition exists

I'm having an issue with a HAVING clause on a string that is created by a GROUP_CONCAT statement.
Running the query:
SELECT row_id, GROUP_CONCAT(cell_id,'-',cell_type) AS flat_row FROM `cells`
GROUP by row_id;
returns the following:
|--------|-------------------------------------------------|
| row_id | flat_row |
|--------|-------------------------------------------------|
| 1 | 1-Text,6-Text,45-Text,5-Number,37-Text,9-Number |
However, running
SELECT row_id, GROUP_CONCAT(cell_id,'-',cell_type) AS flat_row FROM `cells`
GROUP by row_id
HAVING flat_row = '1-Text,6-Text,45-Text,5-Number,37-Text,9-Number';
returns 0 records.
I was expecting to see the same result, does anyone know why the result is empty?
The goal here is to check whether the database contains rows that have the exact cell composition provided in the HAVING clause.
The issue has been resolved. It was a combination of making sure that the order of the string was always the same on both sides of the comparison and properly escaping backslashes in the expected data. Thanks to Caius Jard and Bill Karwin for pointing me in the right direction!

MySQL JSON extract values only if there value > 1

I have the following table:
+-------------+----------------+
| id | server |
+-------------+----------------+
| 1 | ["1", "15"] |
+-------------+----------------+
I need to get only value that is grather that 1 so in above example i need to get from output only 15
I try using this:
SELECT
JSON_EXTRACT(server, "$[*]") as server
FROM streams
WHERE JSON_EXTRACT(server, "$[*]") != JSON_QUOTE('1')
AND id=1;
But i always get ["1", "15"] and need to get ["15"].
Unfortunately, you can't do this with MySQL's JSON_EXTRACT and JSON_SEARCH functions as they perform extraction and exact matching (not comparison) respectively. So, you have two options:
Normalise the table and have server values into a new column (recommended)
Fetch all the values and perform the filtering in service layer
I added this:
SELECT CASE WHEN
JSON_UNQUOTE(JSON_SEARCH(server, 'all', 1)) IS NULL THEN
JSON_REMOVE(server, '$."1"')
ELSE
JSON_REMOVE(server, JSON_UNQUOTE(JSON_SEARCH(server, 'one', 1)))
END AS server
FROM streams WHERE id=2 AND server NOT LIKE '%[]%';
Now it works but if ["1"] is only 1 in json column i get []...a added NOT LIKE '%[]%' but it prints out always []...where i need to add to get no results found from mysql?

Excluding nulls from row_to_json() result in PostgreSQL

I want to convert the rows of a record set to JSON, but not include any null entries that are just going to end up being undefined in JavaScript anyway. For example, suppose I have the table testdata with entries
id | prop1 (integer) | prop2 (text)
-------------------------------------
1 | 42 | 'Answer'
2 | NULL | 'No prop one'
3 | 0 | NULL
and then execute
SELECT row_to_json(testdata) FROM testdata
What I get is:
{"id":"1","prop1":"42","prop2":"Answer"}
{"id":"2","prop1":null,"prop2":"No prop one"}
{"id":"3","prop1":"0","prop2":null}
But instead, what I want is:
{"id":"1","prop1":"42","prop2":"Answer"}
{"id":"2","prop2":"No prop one"}
{"id":"3","prop1":"0"}
Is this possible? According to the JSON functions documentation for PostgreSQL 9.3, there's only one extra option or parameter for row_to_json, but setting pretty_bool=true doesn't remove the nulls, so it seems as if the answer may be no. But this also seems as if it's a very obvious and useful function, so I'm hoping that somebody else has found something I've missed.
My end goal is to retrieve the records in JavaScript with a GET call to a PHP page. Am I better off building the JSON in PHP from a more standard recordset, instead of using PostgreSQL's JSON routines?
Postgres 9.5 introduces json_strip_nulls function, that seems to do exactly what you want.
Looks like future versions of the function may have an 'ignore nulls' option - https://commitfest.postgresql.org/action/patch_view?id=1496

Sort Array results based on variable Algorithm - MYSQL & PHP

I have an array nested within a PHP while loop that outputs a set of forum posts a number of times. I want to sort the array results based on an algorithm - however I do not want to hardcode the algorithm so I can test different variables at a later date. NB - I'm not looking to sort the items within the array, but rather the final output which when looped will output the array 20+ times.
Currently I have 2 Tables - the Forum table with loads of rows (3000 +):
id | name | date_add | votes | ... |
1 | Test Name | 1234567890 | 2 | ... |
... | ... | ... | ... | ... |
The other table contains the Algorithm variables that I want to pass through to the calculation and has only 1 row:
id | vote_reduction | time_variable | gravity |
1 | 1 | 2 | 1.8 |
The specific algorithm I'm using sorts the information based on how log it has been live (in hours), how many votes it has and the gravity factor makes it more sensitive to time. In full:
(votes - vote_reduction)/((Hours Live + time_variable) ^ gravity)
So far I've managed to get this far, and something is going wrong but I can't quite figure it out:
SELECT forum.*,
((forum.votes - algorithm.vote_reduction)/POW(((TIMESTAMPDIFF(HOUR, SYSDATE(), forum.date_add)) + algorithm.time_variable),algorithm.gravity)) AS algorithm.al,
forum.name, forum.id
FROM forum as forum
LEFT JOIN algorithm AS algorithm ON (algorithm.id='1')
ORDER BY algorithm.al
Any ideas?
I haven't tested the results of the algorithm, but the query returns a result for al if you just remove algorithm. from algorithm.al. I don't think you can make a column alias that acts like it's part of a table. What's confusing me is that you say that it's running on your machine. It's not running on SQL Fiddle and is throwing an error.
SELECT forum.*,
((forum.votes - algorithm.vote_reduction)/POW(((TIMESTAMPDIFF(HOUR, SYSDATE(), forum.date_add)) + algorithm.time_variable),algorithm.gravity)) AS al
FROM forum AS forum
LEFT JOIN algorithm AS algorithm ON (algorithm.id='1')
ORDER BY al
Link to SQL fiddle
There are a few errors in the code as follows:
Making an alias with the name "algorithm" clashes with a MySQL
clause also called ALGORITHM
The calculation (at least the way it is
edited above) creates too many values in the POW clause
Encapsulating all declared aliases in ' ' makes the code more full
proof - but the ORDER BY clause doesn't like quotation marks (so remove them there)
The SYSDATE() and forum.date_add fields are in different formats -
the latter being a timestamp
To fix:
SELECT forum.*, TIMESTAMPDIFF(HOUR, from_unixtime(bd.date_add), NOW()) as 'timedif'
((forum.votes - alg.vote_reduction)/POW(('timedif' + alg.time_variable),alg.gravity)) AS 'al'
FROM forum AS forum
LEFT JOIN algorithm AS 'alg' ON (alg.id='1')
ORDER BY al

SQL Padding with zeros(LPAD) in a Database independent way

I have a table like the following :
code ---> INTEGER
name ---> CHAR
+------+------+
| code | name |
+------+------+
| 1 | aa |
| 2 | bb |
| 3 | cc |
I want to pad with left zeros the code field in this way :
SELECT LPAD(code,5,'0') FROM table;
This query works well in MySQL but it doesn't work on SQL Server and on PostgreSQL, i'm looking for a query that work on all databases or at least on these four :
MySQL
PostgreSQL
MSSQL
Firebird
without any changes . Is there a solution ?
The correct answer is "do this in your client".
There is no single solution at the RDBMS level
However, for SQL Server 2012 (yes, next release), PostgreSQL and MySQL you can do this:
RIGHT(CONCAT('00000', code), 5)
Newer PostgreSQL does have LPAD, SQL Server doesn't
The various FORMAT functions are incompatible (but again need to wait until SQL Server 2012)
The RIGHT is consistent, but string concatenation operators are different
The CONCAT function is added in SQL Server 2012
Kind of weak, but one option is to prepend a number of zeroes to the front, and then take the last x characters from the right.
For example,
select '0000000000' || code from table;
will produce
00000000001
00000000002
00000000003
Then substring the results would give you
select substr('0000000000' || code, -5) from table;
00001
00002
00003
I can't recall if the concatenate and substring functions are the same in those four databases. But I guessed that perhaps you are looking for a way to do it that is more generic than what you are already doing, and that might be it. Apologies for the overall ugliness though.
In Firebird 2.5 you can use a query like this:
select right('00000' || cast(code as varchar(20)), 5) from table