On 07/07/18 19:47, E.Pasma wrote:
But the ideas allow a parameter name to be identical to a column name,
which must be an error.

While I might prefer that to be the case, it's actually not. We do not have the ability for column expressions to reference other columns, so there is no ambiguity even if a parameter were to be named the same as a column. It's also currently permissible for multiple columns to have the same name.

CREATE TABLE x (a, b);
INSERT INTO x VALUES (1, 2), (3, 4);
CREATE VIEW y AS SELECT a, b AS a FROM x;
CREATE VIEW z (a, a) AS SELECT * FROM x;
SELECT a, b AS a FROM x;
a           a
----------  ----------
1           2
3           4
SELECT * FROM y;
a           a:1
----------  ----------
1           2
3           4
SELECT * FROM z;
a           a:1
----------  ----------
1           2
3           4

The handling varies a little bit between bare SELECT statements and SELECTs wrapped in views. The latter appends a suffix to identical column names, but the former does not.

I think the only rule would be that no two parameters can have the same name.

So why not a single column list and a modifier to turn a column into
an argument?

CREATE VIEW double (result, arg HIDDEN) AS SELECT arg * 2;
SELECT * FROM numbers, double(x);

I did mention HIDDEN as an option in my original post, though not with the syntax you suggest:

http://sqlite.1065341.n5.nabble.com/Idea-defining-table-valued-functions-directly-in-SQL-td102368.html

At the time I wasn't considering the optional parenthesized output column-name list following the view name, since frankly I never use it. I was thinking only of the SELECT statement, which also supplies the output column names by means of AS clauses, or defaulting to using the input expressions themselves as the names. Thus I allowed HIDDEN as a column modifier in the SELECT clause, roughly copying the way virtual table-valued functions currently work. (I also suggested saying PARAMETER instead of HIDDEN to be a bit clearer about its function.)

If I understand you correctly, your idea is essentially to take this approach but move the HIDDEN columns (i.e., parameters) from the SELECT statement to the output column name list.

I have two issues with this. One is the fact that the output column name list is optional, but now it would become required, at the cost of the user having to retype the output column names even in cases where the default is already good, or even if the user would have preferred to use AS to name the output columns (which is what I do).

The second issue is one I had with my own idea as well, though I was inarticulate about it. Whether the parameters are listed in the output column name list or in the output column expression list, either way we're interspersing outputs with inputs.

All that said, I do prefer your idea over mine. Having the parameter names in the same list as the output column names may be mildly confusing though overall okay with me, but I find my original idea of having the parameter names in the same list as the output column expressions to be off-the-charts weird, which is why I said in my original email that I do not recommend using HIDDEN.

The bottom line for me is that at this point, my preference still goes to the following:

CREATE VIEW double (result) PARAMETERS (arg) AS SELECT arg * 2;
SELECT * FROM numbers, double(x);
WITH double (result) PARAMETERS (arg) AS (SELECT arg * 2)
SELECT * FROM numbers, double(x);

What if a parameter name happens to match a column name in one (or
more) of the tables being pulled in by a FROM clause?  A table name
qualifier is needed to disambiguate.  It could be the function name,
though it could be clearer to do like upsert ("excluded") and have a
special token, e.g.  "parameters".  (cf.
https://sqlite.org/lang_UPSERT.html)

This side idea is more powerful than just to disambiguate column
names. It tells me that a column is pulled from outside the view. An
explicit parameter list is not even needed.

That's really not what I had in mind. I wasn't thinking of FROM clauses outside the view, rather those inside.

CREATE TABLE people (name, age);
INSERT INTO people VALUES ('Bob', 33), ('Jen', 19), ('Liz', 30);

CREATE VIEW older PARAMETERS (name, otherName) AS
SELECT t1.age > t2.age AS older
  FROM people AS t1 WHERE t1.name = parameters.name
     , people AS t2 WHERE t2.name = parameters.name;

SELECT t1.name AS name
     , t2.name AS otherName
     , older(t1.name, t2.name)
  FROM people AS t1
     , people AS t2
 WHERE t1.name != t2.name;

name  otherName  older
----  ---------  -----
Bob   Jen        1
Bob   Liz        1
Jen   Bob        0
Jen   Liz        0
Liz   Bob        0
Liz   Jen        1

SELECT t1.name AS senior
     , t2.name AS junior
  FROM people AS t1
     , people AS t2
 WHERE older(t1.name, t2.name);

senior  junior
------  ------
Bob     Jen
Bob     Liz
Liz     Jen

The column must only exist in the view specification.

CREATE VIEW double (arg, result) AS
SELECT PARAMETERS.arg, PARAMETERS.arg * 2;
SELECT * FROM numbers, double ON arg=x;

Hmm, that's something I've not considered before: identifying parameters as such everywhere they are used, rather than only in some declaration.

However, even though this works as a function, its usage won't resemble other table-valued functions. Arguments aren't explicitly "passed" to the function whereupon they are bound to parameters. Rather, this binding is implied by automatically matching up names from elsewhere.

I fear the precise semantics might be too hard to define and understand. An interface resembling more traditional function calls would be easier to deal with and probably just as powerful in the end.

I want to make a view of the sudoku solver

https://www.sqlite.org/lang_with.html#sudoku

That becomes like below. I have in mind to combine it with a further
view to format the input or output.

Thanks, E.Pasma

CREATE VIEW sudsol(sud,sol) AS
WITH RECURSIVE
   digits(z, lp) AS (
     VALUES('1', 1)
     UNION ALL SELECT
     CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9
   ),
   x(s, ind) AS (
     SELECT PARAMETERS.sud, instr(PARAMETERS.sud, '.')
     UNION ALL
     SELECT
       substr(s, 1, ind-1) || z || substr(s, ind+1),
       instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )
      FROM x, digits AS z
     WHERE ind>0
       AND NOT EXISTS (
             SELECT 1
               FROM digits AS lp
              WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)
                 OR z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1)
                 OR z.z = substr(s, (((ind-1)/3) % 3) * 3
                         + ((ind-1)/27) * 27 + lp
                         + ((lp-1) / 3) * 6, 1)
          )
   )
SELECT PARAMETERS.sud, s FROM x WHERE ind=0;

How about this?

CREATE VIEW sudsol PARAMETERS (sud) AS
--
  WITH digits (z, lp) AS (
VALUES ('1', 1)
 UNION ALL
SELECT CAST (lp+1 AS TEXT)
     , lp+1
  FROM digits
 WHERE lp < 9)
--
     , x (s, ind) PARAMETERS (sud) AS (
SELECT sud
     , instr(sud, '.')
 UNION ALL
SELECT substr(s, 1, ind-1) || z || substr(s, ind+1)
     , instr(substr(s, 1, ind-1) || z || substr(s, ind+1), '.')
  FROM x(sud)
     , digits AS z
 WHERE ind
   AND NOT EXISTS (SELECT 1
                     FROM digits AS lp
                    where z.z = substr(s, (ind-1)/9*9 + lp, 1)
                       or z.z = substr(s, (ind-1)%9 + (lp-1)*9 + 1, 1)
                       or z.z = substr(s, (ind-1)/3%3*3
                                        + (ind-1)/27*27 + lp
                                        + (lp-1)/3*6, 1)))
--
SELECT s FROM x(sud) WHERE NOT ind;

SELECT sudsol(
    '53.'||'.7.'||'...'
 || '6..'||'195'||'...'
 || '.98'||'...'||'.6.'

 || '8..'||'.6.'||'..3'
 || '4..'||'8.3'||'..1'
 || '7..'||'.2.'||'..6'

 || '.6.'||'...'||'28.'
 || '...'||'419'||'..5'
 || '...'||'.8.'||'.79');

Rather than empower x to directly see sudsol's parameter, I declare both sudsol and x to be table-valued functions, then I pass the argument (terminology: parameter value) to each invocation of x. This is more explicit and requires less magic on the part of SQLite to figure out where everything is coming from when faced with nested functions.

Also, witness my lame attempt to format the input. :^)

By the way, I'm unclear why it's okay to simply say "lp" in the above indexing expressions, rather than "lp.lp" which is what I believe is meant.

--
Andy Goth | <andrew.m.goth/at/gmail/dot/com>
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to