The SQL filter clause: selective aggregates
modern-sql.com
modern-sql.com
Want a filter clause? Got it.
Need a weighted distinct count? Now it's part of the language.
Also, you can rephrase a lot of these SQL features as subqueries. It's surprising how many database bugs you can find when you do it. Not so much in Postgres, but I probably found a dozen in Redshift. I mean rephrasing this:
select
sum(x) filter (where x < 5),
sum(x) filter (where x < 7)
from
generate_series(1,10,1) s(x)
;
as this(where t is either a permanent table, view, or CTE as appropriate): with t as (
select * from generate_series(1,10,1) s(x)
)
select
(select sum(x) from t where x < 5),
(select sum(x) from t where x < 7)
;
Though for Postgres the filter will likely have better performance.I find subselects are more predictable, but I wouldn't say they're generally more performant. The explain plan's tree maps more closely to the subquery dependency tree with selects, so someone tweaking their query and staring at the explain plan to get it how they want will have an easier time with the subselect strategy.
Be careful of CTEs if you try that, though. A long chain of CTEs with the transformation I gave is almost guaranteed to give a bad plan(unless you want seq scans all the way down).
http://people.csail.mit.edu/matei/papers/2015/sigmod_spark_s...
Nonsense, Scala is arguably leading the way in the statically typed composable query dsl department; see Slick [1] and Quill [2] among others.
Outside of Haskell's Esqueleto I am not aware of any statically typed query dsl that comes remotely close to the aforementioned. LINQ to SQL/Objects provides static query generation but doesn't compose; beyond that, what is there?
[1] https://github.com/slick/slick [2] https://github.com/getquill/quill
How do you mean? The result of a LINQ query is a sequence that can be used as the input of another LINQ query.
If you have an example of .NET based query composition to share I'd like to see it; last I checked there was no such functionality available.
It's only after you force it to materialize (I.e. call ToList) that you can't further "compose" it.
My guess is that such extensions, while useful, are somewhat marginalised features in terms of usage. Thus, no one ever learns them formally and just Googles for what they need -- if it comes up -- and get the CASE solution, in this case (pun unintentional). Hence perpetuating that pattern. Also, of course, the CASE solution is a lot more powerful as the returned expression, that gets fed into the aggregate function, can be basically anything.
Many things — e.g., Pivot — can be understood way more easily using FILTER rather than CASE.
* http://docs.ibis-project.org/sql.html#aggregates-considering...
* https://github.com/cloudera/ibis/tree/master/ibis/sql (PostgreSQL, Presto, Redshift, SQLite, Vertical)
* https://github.com/cloudera/ibis/blob/master/ibis/sql/alchem... (SQLAlchemy)
SELECT a, COUNT(b) OVER (PARTITION BY c) FROM T;
https://cwiki.apache.org/confluence/display/Hive/LanguageMan...
BTW, SQL seems like a terrible language. For example, why would it need to enforce ordering for keywords like ORDER BY, WHERE, GROUP BY? So many times I had made a mistake that boiled down to putting them in the correct order...
* The from clause retrieves records from data sources like set functions, tables, or views.
* The on/using clause joins tables
* The where clause filters out records
* The group by clause assigns records to buckets
* The having clause filters out records
* The select clause runs
* The order by sorts
* The limit clause picks records
In this query:
> select sum(1) over () from (select 1 a) x join (select 1 a) y using (a) where 1 = 1 group by true having true order by 1 limit 1;
The only out-of-place component is the select and window function(which runs after the group by clause). In a more complex query with multiple selects in scope, the order of terms helps remind you which parts are running in which order.
Note that the optimizer won't strictly enforce the order; it's just a guide to interpret what the results should be.
If you need to do something out-of-order, you can use a subselect:
> select * from (select sum(1) over () from (select 1 a) x join (select 1 a) y using (a) where 1 = 1 group by true having true limit 1 ) x order by 1;
Here, I've swapped the limit clause and the order-by clause, although you can still see the order of operations in the explain plan being separated by a 'Subquery scan'.
I think you mean "The having clause filters out buckets", right?
The reason you give is too trivial to justify calling it "a terrible language"
Also: The fact that everyone run (even if eventually fail) for a ORM instead of SQL, or the way people imagine NOSQL is "better" -is very telling is NO SQL- show this.
The relational model is so simple and powerfull, but SQL is not a good seller of the idea.
I suppose it would be interesting if you could use something like the llvm to target a DB's core features, but through your language of choice.
I haven't seen anything like that, if it exists. SQL is that standard API today, and ORMs provide the language specific implementation (though sometimes in ways that make it inobvious what the generated SQL will look like).
Personally, although I'm not a researcher, I've become intrigued by ways we model change-over-time in relational databases. Snodgrass's book _Developing Time-Oriented Database Applications in SQL_ is a good entry point to all that, and more recently we have SQL2011's Temporal standard. I still have a lot to read here myself, but I am keen to see what happens in the next ten years in how the relational model can incorporate change.
It's interesting to note that transpiling to SQL is even more popular than the recent trend of transpiling to JavaScript. Every major language has a query builder (many of which end up with syntax similar to Andl). We're abstracting away from SQL and have been for a long time.
With that in mind, I wonder whether we need a new query language so desperately. SQL is so highly optimized in the major RDBMS that any new language would probably compile internally to SQL, meaning it has the same semantics (and is essentially sugar) OR it would be way behind SQL in terms of optimization.
Am I just totally off base here?
I actually don't think I like that approach.
If I transpile my own queries (meaning I use a query builder), then I can cache the generated SQL. There would be some placeholders for arguments, but the query itself doesn't change.
Andl's approach could add significant overhead in certain applications where lots of queries are being executed at once.
And then what happens to EXPLAIN support? Is it harder to debug an Andl query?
nr | date | product | quantity
---+------------+---------+----------
1 | 2016-05-29 | a | 2
2 | 2016-05-29 | a | 7
3 | 2016-05-29 | b | 3
4 | 2016-05-29 | a | 1
5 | 2016-05-30 | b | 5
6 | 2016-05-30 | a | 2
And you want to get daily order totals for each product.Then you do:
SELECT
date,
SUM(quantity) FILTER(WHERE product='a') AS product_a,
SUM(quantity) FILTER(WHERE product='b') AS product_b,
SUM(quantity) AS total
FROM orders
GROUP BY date
ORDER BY date
And the result is date | product_a | product_b | total
-----------+-----------+-----------+-------
2016-05-29 | 10 | 3 | 13
2016-05-30 | 3 | 5 | 8That's because idea of SQL was the same as COBOL - kinda-natural more or less ad-hoc end-user-oriented language.
Codd ('Relational Completeness of Data Base Sublanguages') - “Clearly, the majority of users should not have to learn either the relational calculus or algebra in order to interact with data bases. However, requesting data by its properties is far more natural than devising a particular algorithm or sequence of operations for its retrieval. Thus, a calculus-oriented language provides a good target language for a more user-oriented source language.”
Why does SELECT put the column list at the start instead of the end? For all but the simplest queries, I want to set up my tables and joins and group bys and whatnot and then think about what columns I want from them. Seems kinda cumbersome to start with SELECT * FROM ... and then go back and fill in the columns later.
Why does UPDATE put the SET before the WHERE? Feels like an accident waiting to happen. I got into the habit long ago of writing SET x = x WHERE..., writing the correct WHERE statement, then going back and writing correct/valid sets, just to make sure I don't accidentally execute the query too soon and update the whole table.