On 2017/09/04 12:46 PM, David Wellman wrote:
Hi Ryan,
Thanks for that. It is certainly valid syntax and I'll do some testing to check
that it gives me the correct answer.
It's always a pleasure.
Your email has 'crossed in the post' with my second one and you've answered
something that I asked in that (I'm impressed, how did you do that ?)
No special powers I'm afraid, the question pops up from time to time, so
sometimes we answer preemptively the typical question(s) in stead of
just responding to the actual question.
I understand that the UPDATE and INSERT can only have one main (or target)
table, I completely agree with that. I didn't think of the CTE as being 'the
main referenced' (i.e. target) table.
I have used a different dbms for 20+ years (Teradata) and that allows joins in
UPDATEs (coded in a WHERE clause). It also allows use of a CTE albeit a
slightly different syntax.
Yes, some DBs do allow a JOIN for INSERTs and some even for UPDATEs
though I think that is provided as a matter of convenience rather than
DB SQL Standard, and when you have the luxury of very large code size
for the DB Engine, a very nice-to-have; but the -Lite part of SQLite
means it has to watch its weight, so correlated sub-queries it is.
That said, a CTE is essentially just a sub-query that, in stead of being
correlated, pretends to be a table so you are free to reference it in a
correlated manner (or any other manner) in the subsequent SQL statement
parts. Which is what my changes to your code basically did.
There is one very important difference between a CTE and a Sub-Query - A
CTE can create data out of thin air by virtue of the "Recursive"
functionality. Something that no other query or table or view can do.
Let's say you have a table with calendar events and dates in it and you
would like to list all the days in this month that ISN'T in the
calendar, how would you do that with a normal query?
With a CTE it's easy:
WITH AllDays(DayIdx, DayDate) AS (
SELECT 1, date('now','start_of_month')
UNION ALL
SELECT DayIdx+1, date(DayDate,'+1 days') FROM AllDays WHERE DayIdx < 31
)
SELECT DayDate
FROM AllDays
LEFT JOIN MyCalendar AS C ON C.DayDate = AllDays.DayDate
WHERE C.DayDate IS NULL
;
This will list all the days of the current month that doesn't have a
corresponding entry in the MyCalendar table yet. You can use it to
INSERT or UPDATE any other table like a Boss without resorting to
programming to find missing dates.
Just an example, and I haven't tested it since this is simply a
theoretical discussion so the syntax might be off, but the principle stands.
The "Recursive" engine kicks into gear after the UNION [ALL] statement
when you reference the table to itself, thereby extrapolating itself
until stopped by virtue of the WHERE filter. Note that you can get stuff
to recurse infinitely (needing a manual kill process) if the WHERE
restriction is missing, so be careful. (There's obviously a lot more to
be said about CTEs outside the scope of this post, but I encourage you
to dig into it, it's quite fun. See: http://sqlite.org/lang_with.html )
Cheers!
Ryan
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users