create table x as (select * from person);
select name from x where ...;
there you go, just configure your editor to display "create table x" as "declare x = " ;)or even a version with lazy evaluation:
create view x as (select * from person);
select name from x where ...;SQL just does not have this, it instead has 15 different second class ways to handle tables and queries that try to make up for the fact that they are not first-class values. These include CTEs, table valued functions, views, etc.
https://en.wikipedia.org/wiki/First-class_citizen
If you want to see what queries as first-class values looks like, LINQ in .NET is pretty close. I can actually write a series of queries that build on and compose with each other, like this:
IQueryable<Person> RunQuery(int userSelection)
{
var first = from x in People
select x;
var second = userSelection == 1
? from x in first where x.Birthday > '2000-01-01' select x
: from x in first where x.Name.Contains("Jane") select x;
return DumbJoin(first, second);
}
IQueryable<Person> DumbJoin(IQueryable<Person> first, IQueryable<second>)
{
return from x in second
join y in first on y.Role equals x.Role into g
select g;
}
This query is nonsense, but it just shows you what composition really looks like when queries are first-class values. I wish raw SQL were like this!I doubt you could implement a query planner that would cope with that degree of flexibility. Which means you’d be forced to deal with the mechanics of the query, pushing you away from declarative SQL and into procedural and functional programming. At which point you might as well ditch SQL anyway.
Besides, I don't think it would be as bad as you say. You can approach it as a simple template expansion into flat SQL queries except where a data dependency occurs, at which point template expansion proceeds in stages, one for each dependency.
LINQ on .NET provides most of the composability I'm talking about, although it has a few limitations as well. Still worlds better than raw SQL.
CREATE TABLE data_a AS (SELECT 'a' AS test_case, 1 AS value);
CREATE TABLE data_b AS (SELECT 'b' AS test_case, 2 AS value);
CREATE VIEW data AS (SELECT * FROM data_a UNION ALL SELECT * FROM data_b);
CREATE VIEW complicated_query AS (SELECT test_case, value+1 FROM data);
SELECT * FROM complicated_query WHERE test_case = 'a';
SELECT * FROM complicated_query WHERE test_case = 'b'; CREATE TABLE data_a AS (SELECT 'a' AS test_case, 1 AS value);
CREATE TABLE data_b AS (SELECT 'b' AS test_case, 2 AS value);
CREATE TABLE data_prod AS (SELECT NULL AS test_case, prod_table.value FROM prod_table);
CREATE VIEW data AS (SELECT * FROM data_a UNION ALL SELECT * FROM data_b UNION ALL SELECT * FROM data_prod);
CREATE VIEW complicated_query AS (SELECT test_case, value+1 FROM data);
-- when testing
SELECT * FROM complicated_query WHERE test_case = 'a';
SELECT * FROM complicated_query WHERE test_case = 'b';
-- when in 'production'
SELECT * FROM complicated_query WHERE test_case IS NULL;This perfectly illustrates my point. You had to manually defunctionalize your data model and queries to support what I'm saying should be inherently part of SQL.
1) Only if you define Pascal as only Wirth's very first version. That changed almost immediately.
2) Only if you refuse to equate “pointer to function” with “function”. Which in C, where “everything is a pointer” (a bit like in Unix Linux “everything is a file”), seems rather silly.