From 48a26aa71604b578994b4a534212e4ce9a5e560c Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 03:17:10 +0530 Subject: [PATCH 1/8] Adding Document for CTEs. --- source/tips/cte.rst | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 source/tips/cte.rst diff --git a/source/tips/cte.rst b/source/tips/cte.rst new file mode 100644 index 0000000..d7e4e9f --- /dev/null +++ b/source/tips/cte.rst @@ -0,0 +1,60 @@ +Common Table Expressions AKA WITH Queries +################ + +What are they +------------- + +From Documentation : "WITH provides a way to write auxiliary statements for use in a larger query. These statements, which are often referred to as Common Table Expressions or CTEs, can be thought of as defining temporary tables that exist just for one query. Each auxiliary statement in a WITH clause can be a SELECT, INSERT, UPDATE, or DELETE; and the WITH clause itself is attached to a primary statement that can also be a SELECT, INSERT, UPDATE, or DELETE." + +CTEs help to break huge complicated queries into simpler modules. Apart from making the query more readable, there is huge benefit of getting a subquery materialized once and for all which can be refereed by your main query (by name, we'll get to detail in a while) so that the sub query is not computed-recomputed everytime. +To summarize CTE is kinda short-hand for creating temp table, which we would create usually using something like this : + +.. code-block:: sql + + CREATE TEMP TABLE foo AS SELECT... + +CTEs in PostgeSQL can be divided in 3 parts : +1. Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) +2. Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) +3. Recursive CTEs (Is your head already spining??) + +Examples +-------------------------- + +1. Normal CTE : + +The following CTE is equal to a normal select from employee table + +.. code-block:: sql + +With all_employees AS ( + Select empid, name, salary, deptid FROM tblemployee +) +Select * From all_employees; + +Now, consider that you know well in advance for a query that you will need to select a particular group of Emplyees (beloning to a particular Department) +The above code can be modified to use a where clause. + +.. code-block:: sql + +With all_employees AS ( + Select empid, name, salary, deptid FROM employee Where deptid = 2 +) +Select * From all_employees; + +You can also have chained CTEs, i.e more than one CTEs in one statement, where one CTE uses resultset of previous CTE +For Example: + +.. code-block:: sql + +With all_employees AS ( + Select empid, name, salary, deptid FROM employee Where deptid = 2 +),all_employees_with_deptname As( + Select e.*,d.deptname From all_employees e + Join department d + On e.deptid = d.deptid +) +Select * From all_employees_with_deptname; + +In the above example the all_employees_with_deptname uses all_employees's resultset as a table. + From 5039417145c7d4cc0f67ef8e20a18418e1e56f55 Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 03:24:33 +0530 Subject: [PATCH 2/8] Adding Document for CTEs. --- source/tips/cte.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index d7e4e9f..39b7e99 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -13,10 +13,10 @@ To summarize CTE is kinda short-hand for creating temp table, which we would cre CREATE TEMP TABLE foo AS SELECT... -CTEs in PostgeSQL can be divided in 3 parts : -1. Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) -2. Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) -3. Recursive CTEs (Is your head already spining??) +CTEs in PostgeSQL can be divided in 3 kinds : +- Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) +- Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) +- Recursive CTEs (Is your head already spining??) Examples -------------------------- @@ -27,34 +27,34 @@ The following CTE is equal to a normal select from employee table .. code-block:: sql -With all_employees AS ( - Select empid, name, salary, deptid FROM tblemployee -) -Select * From all_employees; + With all_employees AS ( + Select empid, name, salary, deptid FROM employee + ) + Select * From all_employees; Now, consider that you know well in advance for a query that you will need to select a particular group of Emplyees (beloning to a particular Department) The above code can be modified to use a where clause. .. code-block:: sql -With all_employees AS ( - Select empid, name, salary, deptid FROM employee Where deptid = 2 -) -Select * From all_employees; + With all_employees AS ( + Select empid, name, salary, deptid FROM employee Where deptid = 2 + ) + Select * From all_employees; You can also have chained CTEs, i.e more than one CTEs in one statement, where one CTE uses resultset of previous CTE For Example: .. code-block:: sql -With all_employees AS ( - Select empid, name, salary, deptid FROM employee Where deptid = 2 -),all_employees_with_deptname As( - Select e.*,d.deptname From all_employees e - Join department d - On e.deptid = d.deptid -) -Select * From all_employees_with_deptname; + With all_employees AS ( + Select empid, name, salary, deptid FROM employee Where deptid = 2 + ),all_employees_with_deptname As( + Select e.*,d.deptname From all_employees e + Join department d + On e.deptid = d.deptid + ) + Select * From all_employees_with_deptname; In the above example the all_employees_with_deptname uses all_employees's resultset as a table. From 6c8a10ae50eb060ab66ab07308f9d55ba75e3fa4 Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 03:25:46 +0530 Subject: [PATCH 3/8] Adding Document for CTEs. --- source/tips/cte.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index 39b7e99..7e7905c 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -14,6 +14,7 @@ To summarize CTE is kinda short-hand for creating temp table, which we would cre CREATE TEMP TABLE foo AS SELECT... CTEs in PostgeSQL can be divided in 3 kinds : + - Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) - Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) - Recursive CTEs (Is your head already spining??) From d6b2e4d41a1308360f93b5aeb795e76deb33ec7a Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 04:22:20 +0530 Subject: [PATCH 4/8] Updating CTE list. --- source/tips/cte.rst | 73 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index 7e7905c..2e097e8 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -17,12 +17,13 @@ CTEs in PostgeSQL can be divided in 3 kinds : - Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) - Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) -- Recursive CTEs (Is your head already spining??) +- Recursive CTEs (Is your head already spinning??) Examples -------------------------- 1. Normal CTE : +~~~~~~~~~~~~~~~~~~~~~ The following CTE is equal to a normal select from employee table @@ -59,3 +60,73 @@ For Example: In the above example the all_employees_with_deptname uses all_employees's resultset as a table. +2. Writable CTE : +~~~~~~~~~~~~~~~~~~~~~ + +Writable CTEs allow you to modify data apart from normal CTE functionality, they are ideal for using for UPSERT/MERGE functionality. + +.. code-block:: sql + + With delete_employee AS ( + delete empid = 1 returning * + ) + Select * from delete employee + +It is similar to a normal DELETE but now consider that you keep a count of total employees in your department table so when you perform a delete operation in employee you also need those changes to reflect in department count. + +.. code-block:: sql + With delete_employee AS ( + delete empid = 1 returning * + ),summarise_deletion AS ( + select deptid, count(*) AS count from update_emplyee + group by deptid),update_dept_count_on_del As( + update department d set staffcount = staffcount - count From summarise_deletion Where d.deptid = summarise_deletion.deptid + ) + Select deptid, count(*) From update_dept_count_on_del; + +The above query will calculate deleted emplyees per department and update the department table with respective count (i.e. subtracting the count). + +`Check this if you have time and want to learn in depth about wCTE.`_ + +3. Recursive CTE : +~~~~~~~~~~~~~~~~~~~~~ + +This particular CTE is very useful for handling graph like tables specifically when you need to find a list of child of a particular row upto n-level depth. + +`The following query returns sum of all the multiples of 3 or 5 below 1000, which First Problem on Project Euler.`_ + WITH RECURSIVE t1(a, b) AS ( + VALUES(0,0) + UNION ALL + SELECT CASE CAST(b AS BOOLEAN) + WHEN b % 3 = 0 THEN b + WHEN b % 5 = 0 THEN b + END, + b + 1 + FROM t1 + WHERE b < 1000 + ) + SELECT sum(a) FROM t1 + +Now Consider you have a table which is something like + +.. code-block:: sql + + Create Table Node ( + NodeId INTEGER PRIMARY KEY, + ParentNodeId INTEGER NOT NULL , + ... + ) + +If you want to find all the children of a particular node (Say a node with NodeId 10): + +.. code-block:: sql + + WITH RECURSIVE NodeList AS ( + SELECT Node.* FROM Node Where NodeId = 10 + UNION ALL + SELECT first.* FROM Node AS first + JOIN + NodeList AS second + ON (first.ParentNodeId = second.NodeId) + ) + SELECT * FROM NodeList ORDER BY Order NodeId; \ No newline at end of file From 5adca223f624951f042cd973409b678bc780bc47 Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 04:24:31 +0530 Subject: [PATCH 5/8] Updating CTE list. --- source/tips/cte.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index 2e097e8..94b294c 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -86,16 +86,17 @@ It is similar to a normal DELETE but now consider that you keep a count of total The above query will calculate deleted emplyees per department and update the department table with respective count (i.e. subtracting the count). -`Check this if you have time and want to learn in depth about wCTE.`_ +Check `this`_ if you have time and want to learn in depth about wCTE. 3. Recursive CTE : ~~~~~~~~~~~~~~~~~~~~~ This particular CTE is very useful for handling graph like tables specifically when you need to find a list of child of a particular row upto n-level depth. -`The following query returns sum of all the multiples of 3 or 5 below 1000, which First Problem on Project Euler.`_ +The following query returns sum of all the multiples of 3 or 5 below 1000, which `First Problem on Project Euler.`_ + WITH RECURSIVE t1(a, b) AS ( - VALUES(0,0) + VALUES(0,0) UNION ALL SELECT CASE CAST(b AS BOOLEAN) WHEN b % 3 = 0 THEN b From b5a1746ac750b93d58eac70c40afebc2fed6ef88 Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 04:26:38 +0530 Subject: [PATCH 6/8] Updating CTE list. Formatting Killing Me. Why You Know Learn reST.?? :P --- source/tips/cte.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index 94b294c..e55ac07 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -94,17 +94,19 @@ Check `this`_ + +.. code-block:: sql WITH RECURSIVE t1(a, b) AS ( VALUES(0,0) UNION ALL - SELECT CASE CAST(b AS BOOLEAN) - WHEN b % 3 = 0 THEN b - WHEN b % 5 = 0 THEN b - END, - b + 1 - FROM t1 - WHERE b < 1000 + SELECT CASE CAST(b AS BOOLEAN) + WHEN b % 3 = 0 THEN b + WHEN b % 5 = 0 THEN b + END, + b + 1 + FROM t1 + WHERE b < 1000 ) SELECT sum(a) FROM t1 From ca2323398ac74e4d55f28013e2686c449a2fdd1b Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 04:31:44 +0530 Subject: [PATCH 7/8] Final Commit For CTE I wish there was markdownpad like tool for .rst files. Formatting ate more time than writing the content. phewww.. --- source/tips/cte.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index e55ac07..f49c1fb 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -4,9 +4,12 @@ Common Table Expressions AKA WITH Queries What are they ------------- -From Documentation : "WITH provides a way to write auxiliary statements for use in a larger query. These statements, which are often referred to as Common Table Expressions or CTEs, can be thought of as defining temporary tables that exist just for one query. Each auxiliary statement in a WITH clause can be a SELECT, INSERT, UPDATE, or DELETE; and the WITH clause itself is attached to a primary statement that can also be a SELECT, INSERT, UPDATE, or DELETE." +From Documentation : "WITH provides a way to write auxiliary statements for use in a larger query. +These statements, which are often referred to as Common Table Expressions or CTEs, can be thought of as defining temporary tables that exist just for one query. +Each auxiliary statement in a WITH clause can be a SELECT, INSERT, UPDATE, or DELETE; and the WITH clause itself is attached to a primary statement that can also be a SELECT, INSERT, UPDATE, or DELETE." -CTEs help to break huge complicated queries into simpler modules. Apart from making the query more readable, there is huge benefit of getting a subquery materialized once and for all which can be refereed by your main query (by name, we'll get to detail in a while) so that the sub query is not computed-recomputed everytime. +CTEs help to break huge complicated queries into simpler modules. +Apart from making the query more readable, there is huge benefit of getting a subquery materialized once and for all which can be refereed by your main query so that the sub query is not computed-recomputed everytime. To summarize CTE is kinda short-hand for creating temp table, which we would create usually using something like this : .. code-block:: sql @@ -132,4 +135,7 @@ If you want to find all the children of a particular node (Say a node with NodeI NodeList AS second ON (first.ParentNodeId = second.NodeId) ) - SELECT * FROM NodeList ORDER BY Order NodeId; \ No newline at end of file + SELECT * FROM NodeList ORDER BY Order NodeId; + +To understand it's working and also to have a dataset and live example kindly read and follow `this blog post`_ Mr. Depesz. + From 581a98ab039059039dc04d5dcb06a95a34357a4b Mon Sep 17 00:00:00 2001 From: Anuj Patel Date: Fri, 9 Aug 2013 04:33:21 +0530 Subject: [PATCH 8/8] Final Commit For CTE Far from it I guess, typos. --- source/tips/cte.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tips/cte.rst b/source/tips/cte.rst index f49c1fb..d45421e 100644 --- a/source/tips/cte.rst +++ b/source/tips/cte.rst @@ -18,7 +18,7 @@ To summarize CTE is kinda short-hand for creating temp table, which we would cre CTEs in PostgeSQL can be divided in 3 kinds : -- Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SLECTs.) +- Normal CTEs (Allows to make the results of queries available to other queries in the same statement. Only SELECTs.) - Writable CTEs (Normal CTEs + UPDATEs, DELETEs and INSERTs) - Recursive CTEs (Is your head already spinning??)