From 8692f05f14114ee18cb0769d96ce4652ebabe9aa Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Tue, 11 Jul 2023 03:45:54 +0100 Subject: [PATCH] Add content for SQL roadmap --- public/og-images/sql-roadmap.png | Bin 97567 -> 105262 bytes .../100-acid.md | 63 ++---------- .../100-what-are-relational-databases.md | 54 ++++++++++ .../101-rdbms-benefits-limitations.md | 27 +++++ .../100-introduction/102-sql-vs-nosql.md | 43 ++++++++ .../sql/content/100-introduction/index.md | 18 ++++ .../content/101-basic-syntax/100-keywords.md | 60 +++++++++++ .../101-basic-syntax/101-data-types.md | 82 +++++++++++++++ .../content/101-basic-syntax/102-operators.md | 61 ++++++++++++ .../sql/content/101-basic-syntax/index.md | 68 +++++++++++++ .../101-basic-syntax/statements/100-select.md | 54 ++++++++++ .../101-basic-syntax/statements/101-insert.md | 37 +++++++ .../101-basic-syntax/statements/102-update.md | 45 +++++++++ .../101-basic-syntax/statements/103-delete.md | 30 ++++++ .../101-basic-syntax/statements/index.md | 1 + .../sql/content/102-ddl/100-create-table.md | 52 ++++++++++ .../sql/content/102-ddl/101-alter-table.md | 69 +++++++++++++ .../sql/content/102-ddl/102-truncate-table.md | 39 ++++++++ .../roadmaps/sql/content/102-ddl/index.md | 43 ++++++++ .../sql/content/103-dml/100-select.md | 77 +++++++++++++++ .../roadmaps/sql/content/103-dml/101-from.md | 47 +++++++++ .../sql/content/103-dml/101-insert.md | 48 +++++++++ .../sql/content/103-dml/102-update.md | 53 ++++++++++ .../roadmaps/sql/content/103-dml/102-where.md | 29 ++++++ .../sql/content/103-dml/103-delete.md | 37 +++++++ .../sql/content/103-dml/103-order-by.md | 55 +++++++++++ .../sql/content/103-dml/104-group-by.md | 68 +++++++++++++ .../sql/content/103-dml/105-having.md | 44 +++++++++ .../roadmaps/sql/content/103-dml/106-joins.md | 50 ++++++++++ .../roadmaps/sql/content/103-dml/index.md | 41 ++++++++ .../104-aggregate-queries/100-select.md | 73 ++++++++++++++ .../104-aggregate-queries/101-group-by.md | 57 +++++++++++ .../content/104-aggregate-queries/101-sum.md | 58 +++++++++++ .../104-aggregate-queries/102-count.md | 29 ++++++ .../104-aggregate-queries/102-having.md | 51 ++++++++++ .../content/104-aggregate-queries/103-avg.md | 40 ++++++++ .../content/104-aggregate-queries/104-min.md | 57 +++++++++++ .../content/104-aggregate-queries/105-max.md | 37 +++++++ .../content/104-aggregate-queries/index.md | 80 +++++++++++++++ .../105-data-constraints/100-primary-key.md | 52 ++++++++++ .../105-data-constraints/101-foreign-key.md | 37 +++++++ .../105-data-constraints/102-unique.md | 54 ++++++++++ .../105-data-constraints/103-not-null.md | 40 ++++++++ .../content/105-data-constraints/104-check.md | 64 ++++++++++++ .../sql/content/105-data-constraints/index.md | 93 ++++++++++++++++++ .../106-join-queries/100-inner-join.md | 58 +++++++++++ .../content/106-join-queries/101-left-join.md | 30 ++++++ .../106-join-queries/102-right-join.md | 63 ++++++++++++ .../106-join-queries/103-full-outer-join.md | 63 ++++++++++++ .../content/106-join-queries/104-self-join.md | 44 +++++++++ .../106-join-queries/105-cross-join.md | 37 +++++++ .../sql/content/106-join-queries/index.md | 62 ++++++++++++ .../107-sub-queries/100-types/100-scalar.md | 74 ++++++++++++++ .../107-sub-queries/100-types/101-column.md | 39 ++++++++ .../107-sub-queries/100-types/102-row.md | 43 ++++++++ .../107-sub-queries/100-types/103-table.md | 48 +++++++++ .../107-sub-queries/100-types/index.md | 62 ++++++++++++ .../107-sub-queries/101-nested-subqueries.md | 42 ++++++++ .../102-correlated-subqueries.md | 33 +++++++ .../sql/content/107-sub-queries/index.md | 60 +++++++++++ .../108-advanced-sql-functions/100-numeric.md | 71 +++++++++++++ .../108-advanced-sql-functions/101-round.md | 45 +++++++++ .../101-string/100-concat.md | 41 ++++++++ .../101-string/101-length.md | 53 ++++++++++ .../101-string/102-substring.md | 61 ++++++++++++ .../101-string/103-replace.md | 45 +++++++++ .../101-string/104-upper.md | 35 +++++++ .../101-string/105-lower.md | 38 +++++++ .../101-string/index.md | 91 +++++++++++++++++ .../108-advanced-sql-functions/102-ceiling.md | 24 +++++ .../102-conditional/100-case.md | 47 +++++++++ .../102-conditional/101-nullif.md | 40 ++++++++ .../102-conditional/102-coalesce.md | 28 ++++++ .../102-conditional/index.md | 67 +++++++++++++ .../103-date-time/100-date.md | 76 ++++++++++++++ .../103-date-time/101-time.md | 65 ++++++++++++ .../103-date-time/102-datepart.md | 49 +++++++++ .../103-date-time/103-dateadd.md | 45 +++++++++ .../103-date-time/104-timestamp.md | 45 +++++++++ .../103-date-time/index.md | 47 +++++++++ .../108-advanced-sql-functions/103-floor.md | 30 ++++++ .../108-advanced-sql-functions/104-abs.md | 38 +++++++ .../108-advanced-sql-functions/105-mod.md | 33 +++++++ .../108-advanced-sql-functions/index.md | 69 +++++++++++++ .../sql/content/109-views/100-creating.md | 52 ++++++++++ .../sql/content/109-views/101-modifying.md | 82 +++++++++++++++ .../sql/content/109-views/102-dropping.md | 31 ++++++ .../roadmaps/sql/content/109-views/index.md | 54 ++++++++++ .../110-indexes/100-managing-indexes.md | 48 +++++++++ .../110-indexes/101-query-optimization.md | 66 +++++++++++++ .../roadmaps/sql/content/110-indexes/index.md | 72 ++++++++++++++ .../sql/content/111-transactions/100-acid.md | 9 ++ .../111-transactions/101-isolation-levels.md | 45 +++++++++ .../sql/content/111-transactions/102-begin.md | 43 ++++++++ .../content/111-transactions/103-commit.md | 39 ++++++++ .../content/111-transactions/104-rollback.md | 49 +++++++++ .../content/111-transactions/105-savepoint.md | 60 +++++++++++ .../sql/content/111-transactions/index.md | 52 ++++++++++ .../112-integrity-security/100-constraints.md | 83 ++++++++++++++++ .../101-grant-revoke.md | 46 +++++++++ .../102-security-best-practices.md | 45 +++++++++ .../content/112-integrity-security/index.md | 54 ++++++++++ .../113-stored-procedures-functions.md | 60 +++++++++++ .../100-query-optimization/100-indexes.md | 41 ++++++++ .../101-optimizing-joins.md | 58 +++++++++++ .../102-reducing-subqueries.md | 57 +++++++++++ .../103-selective-projection.md | 27 +++++ .../100-query-optimization/index.md | 65 ++++++++++++ .../101-query-analysis.md | 39 ++++++++ .../content/114-perf-optimization/index.md | 67 +++++++++++++ .../115-advanced-sql/100-recursive-queries.md | 54 ++++++++++ .../115-advanced-sql/101-pivot-unpivot.md | 62 ++++++++++++ .../102-window-functions/100-row-number.md | 43 ++++++++ .../102-window-functions/101-rank.md | 50 ++++++++++ .../102-window-functions/102-dense-rank.md | 44 +++++++++ .../102-window-functions/103-lead.md | 34 +++++++ .../102-window-functions/104-lag.md | 50 ++++++++++ .../102-window-functions/index.md | 44 +++++++++ .../sql/content/115-advanced-sql/103-ctes.md | 59 +++++++++++ .../115-advanced-sql/104-dynamic-sql.md | 50 ++++++++++ .../sql/content/115-advanced-sql/index.md | 74 ++++++++++++++ src/data/roadmaps/sql/content/index.md | 1 + src/data/roadmaps/sql/sql.json | 4 +- 123 files changed, 6012 insertions(+), 59 deletions(-) create mode 100644 src/data/roadmaps/sql/content/100-introduction/100-what-are-relational-databases.md create mode 100644 src/data/roadmaps/sql/content/100-introduction/101-rdbms-benefits-limitations.md create mode 100644 src/data/roadmaps/sql/content/100-introduction/102-sql-vs-nosql.md create mode 100644 src/data/roadmaps/sql/content/100-introduction/index.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/100-keywords.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/101-data-types.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/102-operators.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/index.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/statements/100-select.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/statements/101-insert.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/statements/102-update.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/statements/103-delete.md create mode 100644 src/data/roadmaps/sql/content/101-basic-syntax/statements/index.md create mode 100644 src/data/roadmaps/sql/content/102-ddl/100-create-table.md create mode 100644 src/data/roadmaps/sql/content/102-ddl/101-alter-table.md create mode 100644 src/data/roadmaps/sql/content/102-ddl/102-truncate-table.md create mode 100644 src/data/roadmaps/sql/content/102-ddl/index.md create mode 100644 src/data/roadmaps/sql/content/103-dml/100-select.md create mode 100644 src/data/roadmaps/sql/content/103-dml/101-from.md create mode 100644 src/data/roadmaps/sql/content/103-dml/101-insert.md create mode 100644 src/data/roadmaps/sql/content/103-dml/102-update.md create mode 100644 src/data/roadmaps/sql/content/103-dml/102-where.md create mode 100644 src/data/roadmaps/sql/content/103-dml/103-delete.md create mode 100644 src/data/roadmaps/sql/content/103-dml/103-order-by.md create mode 100644 src/data/roadmaps/sql/content/103-dml/104-group-by.md create mode 100644 src/data/roadmaps/sql/content/103-dml/105-having.md create mode 100644 src/data/roadmaps/sql/content/103-dml/106-joins.md create mode 100644 src/data/roadmaps/sql/content/103-dml/index.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/100-select.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/101-group-by.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/101-sum.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/102-count.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/102-having.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/103-avg.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/104-min.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/105-max.md create mode 100644 src/data/roadmaps/sql/content/104-aggregate-queries/index.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/100-primary-key.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/101-foreign-key.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/102-unique.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/103-not-null.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/104-check.md create mode 100644 src/data/roadmaps/sql/content/105-data-constraints/index.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/100-inner-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/101-left-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/102-right-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/103-full-outer-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/104-self-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/105-cross-join.md create mode 100644 src/data/roadmaps/sql/content/106-join-queries/index.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/100-types/100-scalar.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/100-types/101-column.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/100-types/102-row.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/100-types/103-table.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/100-types/index.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/101-nested-subqueries.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/102-correlated-subqueries.md create mode 100644 src/data/roadmaps/sql/content/107-sub-queries/index.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/100-numeric.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-round.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/100-concat.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/101-length.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/102-substring.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/103-replace.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/104-upper.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/105-lower.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/index.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/102-ceiling.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/100-case.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/101-nullif.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/102-coalesce.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/index.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/100-date.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/101-time.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/102-datepart.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/103-dateadd.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/104-timestamp.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/index.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/103-floor.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/104-abs.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/105-mod.md create mode 100644 src/data/roadmaps/sql/content/108-advanced-sql-functions/index.md create mode 100644 src/data/roadmaps/sql/content/109-views/100-creating.md create mode 100644 src/data/roadmaps/sql/content/109-views/101-modifying.md create mode 100644 src/data/roadmaps/sql/content/109-views/102-dropping.md create mode 100644 src/data/roadmaps/sql/content/109-views/index.md create mode 100644 src/data/roadmaps/sql/content/110-indexes/100-managing-indexes.md create mode 100644 src/data/roadmaps/sql/content/110-indexes/101-query-optimization.md create mode 100644 src/data/roadmaps/sql/content/110-indexes/index.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/100-acid.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/101-isolation-levels.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/102-begin.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/103-commit.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/104-rollback.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/105-savepoint.md create mode 100644 src/data/roadmaps/sql/content/111-transactions/index.md create mode 100644 src/data/roadmaps/sql/content/112-integrity-security/100-constraints.md create mode 100644 src/data/roadmaps/sql/content/112-integrity-security/101-grant-revoke.md create mode 100644 src/data/roadmaps/sql/content/112-integrity-security/102-security-best-practices.md create mode 100644 src/data/roadmaps/sql/content/112-integrity-security/index.md create mode 100644 src/data/roadmaps/sql/content/113-stored-procedures-functions.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/100-indexes.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/101-optimizing-joins.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/102-reducing-subqueries.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/103-selective-projection.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/index.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/101-query-analysis.md create mode 100644 src/data/roadmaps/sql/content/114-perf-optimization/index.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/100-recursive-queries.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/101-pivot-unpivot.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/100-row-number.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/101-rank.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/102-dense-rank.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/103-lead.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/104-lag.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/index.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/103-ctes.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/104-dynamic-sql.md create mode 100644 src/data/roadmaps/sql/content/115-advanced-sql/index.md create mode 100644 src/data/roadmaps/sql/content/index.md diff --git a/public/og-images/sql-roadmap.png b/public/og-images/sql-roadmap.png index e46c88b406f18ba19a970dbac67efa00f8032f20..e56c66cd035385648c262fe63e5194a8dd08ba23 100644 GIT binary patch literal 105262 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≈kk7qh&4b{ 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%0AwNs(NVTS%nJ1j5BF{u7p{X-0Q_z0{j3CS9C#cnY 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�tJoUx@mN-x(C zmIs6(ctw-4!KRK%%V0A}qN;_X0=cEy7!AL))L^Rj@aVIk+%OwOV;TYh^ggA}d;go)~ z!GqPA3!z&P$;)Q79|mj3@0FwLx` zvAl|>+8m8JjH`!VXBGgNSlG}D^##Sb-u;rsUe=c5lS{I^j>A?rut+p zUDChwGCIbt=AbOw_A*VZTV;G#s^AmJqW?ZKduf=?p9vLt%A9O$#f+J%@#LZXUTs&b zo}$u3&$p#x4ukzynsU-IrRoJ?n7i;XM6Fn>bjw^fJErUx0Y09RggBE?a0T6M=V@3} z@;Jw9%PSvDRCWY=-jJ~DD~fh=j_~|*h7o)g3{8x*89Y+TmsedZ)N9OaCrLa}6dEd2 zKj(#=s;IcNji{p0%c5_RaXX)?)BboyfAuq_ml1^~9{2(S<#q4(%OtOco0{FcB*?;} z@bukc+?vs9rf*EbH1a-8+%GAaVJ$ZGC1=kH_8uQG%3igMSUN4=FGVlAW*8Z{qiV=k z?qWd#T34r(^e-}ii+NRPfj=ktncDXP^CI= zZ5Sa!=v~(iU=e$B8^THd(&m~{jZ@Hx{J6#_$cb<+IQq1zUbfBZlhKfn{#dM(#_wJ@ z%?y9X(6r3eVvPvaCLein-irymKQX~T^z0BYtIaP*m|B)8hzU+Zy$vxzNxgxLh#MlI zEBen>xe`oz^jd@%asirL>$liu$Ee^L6G=`7B z7*%~(1}tr(|HS=!?nw>G(l3}j63Y63Cw83YH z)jt)^Rh2$Tj# zWQB~!fuoRY-Rxni@vX8=jx0UWrb=#hOw-FlY16M2&W}Kul==7%HRTwwJ#m&ITm)rG z$TO#ye6T=ll4dFBm2M;eU5*yKzSBZz85JMC<_Gys4{@>9@$AG0&BH?1Kg5VN+#(+2@XM}hF z-o&A-a^0G`oHeRpqv>0XUTQ&MkWX*Htf8}Fh{Cfc1<}R-OEocLWVoGK9k88d7sD6y zuBrIM#*0TLTeXS1?_qla$247p+w$dKGNrNl84E?pR1ukHngJpcqOyr~g+lt5R~=QH zPtZWz&`fZ_uKqf~f52(K^bsQen3Ouz0iy=#hpl;ib>wUy`5g`@KmjgS$VUHbJnPTK zHuxL85krnql?4kc^LrdzmH!Dhs~>caChji(OH6Jmw|2v-2KI`-zg8e6^!W0QCP^-S zHq*chrVoK{d0ILpQOqVVTj<@nyqUYb-!<&NY{=W*{ZO_JueR_s^BRZkR23Y(_s<}7 zqz2p169c6un{`hDCs1?5%=xiFNHBK8}Z!1zAIhSu0=1maG_>FR$}5ZdHh{!6n^_?vZ@NF!RFr6( z=mbn_+2<jJc8Y%| z9rKlHrkWT%`F|lDkSItrgw;4GisFYW_7ikSM0pD8)DAMUPJYba)XBGwqS}yhmJ{aU z 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 BdW{a1nA70VEOD_0hi*MW4pxz!2EapQUnHLt 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 IvUT|X0mX^HmjD0& literal 97567 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 : Not equal + - `>` : Greater than + - `<` : Less than + - `>=`: Greater than or equal + - `<=`: Less than or equal + + Example: + + ```sql + SELECT name, age + FROM students + WHERE age > 18; + ``` + +3. **Logical Operators**: They are used to combine the result set of two different component conditions. These include: + + - `AND`: Returns true if both components are true. + - `OR` : Returns true if any one of the component is true. + - `NOT`: Returns the opposite boolean value of the condition. + + Example: + + ```sql + SELECT * + FROM employees + WHERE salary > 50000 AND age < 30; + ``` + +4. **Bitwise Operators**: These perform bit-level operations on the inputs. Here is a list of these operators: + + - `&` : Bitwise AND + - `|` : Bitwise OR + - `^` : Bitwise XOR + + Bitwise operators are much less commonly used in SQL than the other types of operators. + +Remember, the datatype of the result is dependent on the types of the operands. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/index.md b/src/data/roadmaps/sql/content/101-basic-syntax/index.md new file mode 100644 index 000000000..782654d2e --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/index.md @@ -0,0 +1,68 @@ +# Basic SQL Syntax + +SQL, or Structured Query Language, uses a specific set of commands to interact with a database. It includes the use of keyword-like statements to accomplish several tasks such as creating, deleting, or modifying tables, retrieving, inserting, or modifying data. + +The `SELECT` statement is used to retrieve data from a database. The data returned is stored in a result table, called the result-set. + +```sql +SELECT column1, column2 FROM table_name; +``` + +The `INSERT INTO` statement is used to insert new rows of data in a table. + +```sql +INSERT INTO table_name (column1, column2, column3) +VALUES (value1, value2, value3); +``` + +The `UPDATE` statement is used to modify existing records in a table. + +```sql +UPDATE table_name +SET column1 = value1, column2 = value2 +WHERE condition; +``` + +The `DELETE` statement is used to remove rows from a table. + +```sql +DELETE FROM table_name WHERE condition; +``` + +The `CREATE TABLE` statement is used to create a new table in a database. + +```sql +CREATE TABLE table_name ( + column1 datatype constraints, + column2 datatype constraints, + column3 datatype constraints +); +``` + +The `ALTER TABLE ` statement is used to add, delete/drop or modify columns in the existing table. It is also used to add and drop constraints on the existing table. + +```sql +-- To add a column +ALTER TABLE table_name +ADD column_name datatype; + +-- To delete/drop column +ALTER TABLE table_name +DROP COLUMN column_name; + +-- To modify existing column +ALTER TABLE table_name +MODIFY COLUMN column_name datatype; +``` + +The `DROP TABLE` statement is used to drop an existing table in a database. + +```sql +DROP TABLE table_name; +``` + +Learn more about SQL from the following resources: + +- [SQL Tutorial - Mode](https://mode.com/sql-tutorial/) +- [SQL Tutorial](https://www.sqltutorial.org/) +- [SQL Tutorial - W3Schools](https://www.w3schools.com/sql/default.asp) diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/statements/100-select.md b/src/data/roadmaps/sql/content/101-basic-syntax/statements/100-select.md new file mode 100644 index 000000000..8efb519bd --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/statements/100-select.md @@ -0,0 +1,54 @@ +# SELECT + +The `SELECT` statement is used in SQL to pick out specific data from a database. In other words, it is used to select from the database what you would like to display. The syntax for the `SELECT` statement is fairly straightforward: + +```sql +SELECT column(s) +FROM table +WHERE condition; +``` + +- `column(s)`: Enter the name(s) of the column(s) that you want to display. +- `table`: The name of the table from where you want to retrieve data. +- `WHERE`: Optional. This is a filter to display only the rows where this condition is true. + +For instance, if you wanted to select all data from the "Customers" table, your query would look like this: + +```sql +SELECT * +FROM Customers; +``` +In the above code, the asterisk `*` denotes "all". This will retrieve all of the data in the "Customers" table. + +If you want to select only the "FirstName" and "LastName" columns from the "Customers" table, your query would look like this: + +```sql +SELECT FirstName, LastName +FROM Customers; +``` + +You can also filter using the `WHERE` clause. For example, selecting only the customers who are from "Germany": + +```sql +SELECT * +FROM Customers +WHERE Country='Germany'; +``` + +Finally, you can also sort the results using the `ORDER BY` keyword: + +```sql +SELECT * +FROM Customers +ORDER BY Country; +``` + +This will sort the output in ascending order by the Country column. To sort in descending order, you would add the `DESC` keyword: + +```sql +SELECT * +FROM Customers +ORDER BY Country DESC; +``` + +These are the very basics of the `SELECT` statement in SQL, which is a vital part of working with databases. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/statements/101-insert.md b/src/data/roadmaps/sql/content/101-basic-syntax/statements/101-insert.md new file mode 100644 index 000000000..1f5ac32ff --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/statements/101-insert.md @@ -0,0 +1,37 @@ +# INSERT + +The `INSERT` statement in SQL is used to add new rows of data to a table in the database. There are three forms of the `INSERT` statement: `INSERT INTO` values, `INSERT INTO` set, and `INSERT INTO` select. + +## `INSERT INTO` values + +The basic syntax for `INSERT INTO` values: + +```sql +INSERT INTO table_name (column1, column2, column3, ...) +VALUES (value1, value2, value3, ...); +``` +This form of the `INSERT` statement specifies both the column names and the values to be inserted. + +## `INSERT INTO` set + +In this form, you're able to insert data using the `SET` keyword. Here, you specify each column you want to insert data into, and then the data for that column. + +```sql +INSERT INTO table_name +SET column1 = value1, column2 = value2, ...; +``` + +## `INSERT INTO` select + +The `INSERT INTO SELECT` statement is used to copy data from one table and insert it into another table. Or, to insert data into specific columns from another table. + +```sql +INSERT INTO table_name1 (column1, column2, column3, ...) +SELECT column1, column2, column3, ... +FROM table_name2 +WHERE condition; +``` + +In all cases, if you're inserting data into a table where some columns have default values, you don't need to specify those columns in your `INSERT INTO` statement. + +Note: Be careful when inserting data into a database as SQL does not have a confirm command. So once you execute the insert statement, the records are inserted, and you can't undo the operation. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/statements/102-update.md b/src/data/roadmaps/sql/content/101-basic-syntax/statements/102-update.md new file mode 100644 index 000000000..d6418bae3 --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/statements/102-update.md @@ -0,0 +1,45 @@ +# UPDATE + +The SQL `UPDATE` statement is used to modify the existing data in a database. This statement is very useful when you need to change the values assigned to specific fields in an existing row or set of rows. + +The general syntax for the UPDATE statement is as follows: + +```sql +UPDATE table_name +SET column1 = value1, column2 = value2, ... +WHERE condition; +``` + +- `table_name`: The name of the table where an update will be performed. +- `SET`: This clause specifies the column name and the new value that it should be updated to. +- `column1, column2, ...`: The column names in the table. +- `value1, value2, ...`: The new values that you want to record into the database. +- `WHERE`: This clause specifies the conditions that identify which row(s) to update. + +## Example Usage + +Here's an example that might provide some clarity. For an imaginary `Employees` table: + +| EmployeeID | Name | Position | Salary | +|------------|---------|----------|--------| +| 1 | Jane | Manager | 50000 | +| 2 | John | Clerk | 30000 | +| 3 | Bob | Engineer | 40000 | + +If you want to increase Bob's salary by $5000, you would use: + +```sql +UPDATE Employees +SET Salary = 45000 +WHERE EmployeeID = 3; +``` + +This would permanently change the data in the `Employees` table: + +| EmployeeID | Name | Position | Salary | +|------------|---------|----------|--------| +| 1 | Jane | Manager | 50000 | +| 2 | John | Clerk | 30000 | +| 3 | Bob | Engineer | 45000 | + +Always be careful with the `UPDATE` statement; if you forget the `WHERE` clause, you will update all the rows in the table. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/statements/103-delete.md b/src/data/roadmaps/sql/content/101-basic-syntax/statements/103-delete.md new file mode 100644 index 000000000..0adedd70f --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/statements/103-delete.md @@ -0,0 +1,30 @@ +# DELETE + +The `DELETE` statement in SQL helps you remove existing records from a database. However, keep in mind, it is a destructive operation and may permanently erase data from your database. + +With the `DELETE` statement, you can perform the following: + +1. **Delete All Rows:** + + The `DELETE` statement without a `WHERE` clause deletes all rows in a table. This operation is irreversible. + + Example: + ```sql + DELETE FROM table_name; + ``` + This SQL statement deletes all the records from `table_name`. + +2. **Delete Specific Rows:** + + When combined with the `WHERE` clause, the `DELETE` SQL statement erases specific rows that meet the condition. + + Example: + ```sql + DELETE FROM table_name WHERE condition; + ``` + This instance of the `DELETE` statement deletes records from `table_name` the place where the given `condition` matches. + +It's crucial to use `DELETE` cautiously because it has the potential to either erase certain important rows or entirely empty the table. + + +*Note: The deletion made by the "DELETE" statement is permanent and cannot be undone. Always ensure to have a backup before running a DELETE query, especially when it is on a production database.* \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/101-basic-syntax/statements/index.md b/src/data/roadmaps/sql/content/101-basic-syntax/statements/index.md new file mode 100644 index 000000000..1082095a9 --- /dev/null +++ b/src/data/roadmaps/sql/content/101-basic-syntax/statements/index.md @@ -0,0 +1 @@ +# Statements \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/102-ddl/100-create-table.md b/src/data/roadmaps/sql/content/102-ddl/100-create-table.md new file mode 100644 index 000000000..90f70539a --- /dev/null +++ b/src/data/roadmaps/sql/content/102-ddl/100-create-table.md @@ -0,0 +1,52 @@ +# Create Table + +The `CREATE TABLE` statement in SQL is a Data Definition Language (DDL) command used to create a new table in the database. + +## SQL CREATE TABLE Syntax + +The syntax for SQL `CREATE TABLE` is as follows: + +```sql +CREATE TABLE table_name ( + column1 datatype, + column2 datatype, + column3 datatype, + .... +); +``` + +- `table_name` is the name of the table that you want to create. +- `column1, column2,...` are the columns in the table. +- `datatype` is the data type for the column, such as varchar, int, date, etc. + +## SQL CREATE TABLE Example + +Here is an example of the `CREATE TABLE` statement: + +```sql +CREATE TABLE Employees ( + ID int, + Name varchar(255), + Salary int, + Department varchar(255), + Position varchar(255) +); +``` + +This SQL command creates a new table named `Employees` with five columns, named 'ID', 'Name', 'Salary', 'Department', and 'Position'. The data types are int for the 'ID' and 'Salary', and varchar(255) for the others. + +## SQL CREATE TABLE with NOT NULL + +The `NOT NULL` constraint enforces a column to not accept null values. When creating a new table, you can add this constraint. Here is a practical example: + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Salary int, + Department varchar(255), + Position varchar(255) +); +``` + +In the example above, the 'ID' and 'Name' must always have a value. They cannot be unassigned or undefined. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/102-ddl/101-alter-table.md b/src/data/roadmaps/sql/content/102-ddl/101-alter-table.md new file mode 100644 index 000000000..066d2cdf2 --- /dev/null +++ b/src/data/roadmaps/sql/content/102-ddl/101-alter-table.md @@ -0,0 +1,69 @@ +# Alter Table + +The `ALTER TABLE` command in SQL is used to add, delete/drop, or modify columns in an existing table. It's also useful for adding and dropping constraints such as primary key, foreign key, etc. + +## Add Column + +A single column can be added using the following syntax: + +```sql +ALTER TABLE tableName +ADD columnName datatype; +``` + +To add more than one column: + +```sql +ALTER TABLE tableName +ADD (columnName1 datatype, + columnName2 datatype, + ... + ); +``` + +## Drop Column + +To drop a single column: + +```sql +ALTER TABLE tableName +DROP COLUMN columnName; +``` + +To drop multiple columns: + +```sql +ALTER TABLE tableName +DROP (columnName1, + columnName2, + ... + ); +``` + +## Modify Column + +To modify the datatype of a column: + +```sql +ALTER TABLE tableName +ALTER COLUMN columnName TYPE newDataType; +``` + +## Add/Drop Constraints + +To add constraints: + +```sql +ALTER TABLE tableName +ADD CONSTRAINT constraintName +PRIMARY KEY (column1, column2, ... column_n); +``` + +To drop constraints: + +```sql +ALTER TABLE tableName +DROP CONSTRAINT constraintName; +``` + +In conclusion, `ALTER TABLE` in SQL lets you alter the structure of an existing table. This is a powerful command that lets you dynamically add, modify, and delete columns as well as the constraints placed on them. It ensures you are more flexible in dealing with changing data storage requirements. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/102-ddl/102-truncate-table.md b/src/data/roadmaps/sql/content/102-ddl/102-truncate-table.md new file mode 100644 index 000000000..9577a8c1f --- /dev/null +++ b/src/data/roadmaps/sql/content/102-ddl/102-truncate-table.md @@ -0,0 +1,39 @@ +# Truncate Table + +The `TRUNCATE TABLE` statement is a Data Definition Language (DDL) operation that is used to mark the extents of a table for deallocation (empty for reuse). The result of this operation quickly removes all data from a table, typically bypassing a number of integrity enforcing mechanisms intended to protect data (like triggers). + +It effectively eliminates all records in a table, but not the table itself. Unlike the `DELETE` statement, `TRUNCATE TABLE` does not generate individual row delete statements, so the usual overhead for logging or locking does not apply. + +## Syntax + +In SQL, the `TRUNCATE TABLE` statement is quite simple: + +```sql +TRUNCATE TABLE table_name; +``` + +In this command, "table_name" refers to the name of the table you wish to clear. + +## Example + +If you have a table named `Orders` and you want to delete all its records, you would use: + +```sql +TRUNCATE TABLE Orders; +``` + +After executing this statement, the `Orders` table would still exist, but it would be empty. + +Remember, while `TRUNCATE TABLE` is faster and uses fewer system and transaction log resources than `DELETE`, it does not invoke triggers and cannot be rolled back, so use with caution. + +## Limitations + +Truncate preserves the structure of the table for future use. But you can't truncate a table that: + +- Is referenced by a FOREIGN KEY constraint. (You can truncate a table that has a foreign key that references itself.) +- Participates in an indexed view. +- Is published by using transactional replication or merge replication. + +If you try to truncate a table with a foreign key constraint, SQL Server will prevent you from doing so and you will have to use the `DELETE` statement instead. + +For partitioned tables, `TRUNCATE TABLE` removes all rows from all partitions. The operation is not allowed if the table contains any LOB columns - `varchar(max), nvarchar(max), varbinary(max), text, ntext, image, xml`, or if the table contains any filestream columns or spatial geo, geography, geometry, and hierarchyid data type columns, or any columns of CLR user-defined data types. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/102-ddl/index.md b/src/data/roadmaps/sql/content/102-ddl/index.md new file mode 100644 index 000000000..3e9c43e15 --- /dev/null +++ b/src/data/roadmaps/sql/content/102-ddl/index.md @@ -0,0 +1,43 @@ +# Data Definition Language (DDL) + +Data Definition Language (DDL) is a subset of SQL. Its primary function is to create, modify, and delete database structures but not data. The commands in DDL are: + +1. `CREATE`: This command is used to create the database or its objects (like table, index, function, views, store procedure, and triggers). + + ```sql + CREATE TABLE table_name ( + column1 data_type(size), + column2 data_type(size), + ... + ); + ``` + +2. `DROP`: This command is used to delete an existing database or table. + + ```sql + DROP TABLE table_name; + ``` + +3. `ALTER`: This is used to alter the structure of the database. It is used to add, delete/drop or modify columns in an existing table. + + ```sql + ALTER TABLE table_name ADD column_name datatype; + ALTER TABLE table_name DROP COLUMN column_name; + ALTER TABLE table_name MODIFY COLUMN column_name datatype(size); + ``` + +4. `TRUNCATE`: This is used to remove all records from a table, including all spaces allocated for the records which are removed. + + ```sql + TRUNCATE TABLE table_name; + ``` + +5. `RENAME`: This is used to rename an object in the database. + + ```sql + RENAME TABLE old_table_name TO new_table_name; + ``` + +Remember: In DDL operations, `COMMIT` and `ROLLBACK` statement cannot be performed because the MySQL engine automatically commits the changes. + +Remember to replace `table_name`, `column_name`, `datatype(size)`, `old_table_name`, and `new_table_name` in the examples above with your actual table names, column names, data types and sizes, and the old or new table names you want to specify. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/100-select.md b/src/data/roadmaps/sql/content/103-dml/100-select.md new file mode 100644 index 000000000..0208e572c --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/100-select.md @@ -0,0 +1,77 @@ +# SELECT + +The `SELECT` statement in SQL is majorly used for fetching data from the database. It is one of the most essential elements of SQL. + +## Syntax + +Here's how your `SELECT` command will look like: + +```sql +SELECT column1, column2, ... +FROM table_name; +``` +If you want to select all the columns of a table, you can use `*` like this: +```sql +SELECT * FROM table_name; +``` +## Example + +For instance, consider we have a table `EMPLOYEES` with columns `name`, `designation`, and `salary`. We can use `SELECT` in the following way: + +```sql +SELECT name, designation FROM EMPLOYEES; +``` +This will retrieve all the names and designations of all employees from the table `EMPLOYEES`. + +## SELECT DISTINCT + +The `SELECT DISTINCT` statement is used to return only distinct (different) values. The DISTINCT keyword eliminates duplicate records from the results. + +Here's how you can use it: + +```sql +SELECT DISTINCT column1, column2, ... +FROM table_name; +``` + +For example, if we want to select all unique designations from the `EMPLOYEES` table, the query will look like this: + +```sql +SELECT DISTINCT designation FROM EMPLOYEES; +``` + +## SELECT WHERE + +`SELECT` statement combined with `WHERE` gives us the ability to filter records based on a condition. + +Syntax: + +```sql +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` +For example, to select employees with salary more than 50000, you can use this query: + +```sql +SELECT * FROM EMPLOYEES WHERE salary > 50000; +``` + +## SELECT ORDER BY + +Using `SELECT` statement in conjunction with `ORDER BY`, we can sort the result-set in ascending or descending order. + +Syntax: + +```sql +SELECT column1, column2, ... +FROM table_name +ORDER BY column ASC|DESC; +``` +For example, to select all employees and order them by their name in ascending fashion: + +```sql +SELECT * FROM EMPLOYEES ORDER BY name ASC; +``` + +Remember that the default sort order is ascending if the ASC|DESC parameter is not defined. diff --git a/src/data/roadmaps/sql/content/103-dml/101-from.md b/src/data/roadmaps/sql/content/103-dml/101-from.md new file mode 100644 index 000000000..0bc6e3cfb --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/101-from.md @@ -0,0 +1,47 @@ +# FROM + +The `FROM` clause in SQL specifies the tables from which the retrieval should be made. It is an integral part of `SELECT` statements and variants of `SELECT` like `SELECT INTO` and `SELECT WHERE`. `FROM` can be used to join tables as well. + +Typically, `FROM` is followed by space delimited list of tables in which the SELECT operation is to be executed. If you need to pull data from multiple tables, you would separate each table with a comma. + +Here are some examples: + +**Example 1 - Simple Usage** + +If you've a table called `employees`, you can select all employees' data like this: + +```sql +SELECT * +FROM employees; +``` +In this example, `*` means "all columns". So, `SELECT * FROM employees;` will retrieve all data from the `employees` table. + +**Example 2 - FROM with Multiple Tables** + +If you've multiple tables, say `employees` and `departments`, and you want to select data from both, you can do the following: + +```sql +SELECT employees.name, departments.department +FROM employees, departments +WHERE employees.dept_id = departments.dept_id; +``` + +In this example, the `FROM` clause is following by two tables: `employees` and `departments`. `employees.name` and `departments.department` indicate that we're selecting the `name` column from the `employees` table and the `department` column from the `departments` table. + +Remember, always respect the order of operations in SQL. The `FROM` clause works only after tables are identified. + +In complex SQL queries where you might need to pull data from multiple tables, aliases are used to temporarily rename the tables within the individual SQL statement. + +**Example 3 - FROM with Aliases** + +Below is an example of a `FROM` clause with aliases: + +```sql +SELECT e.name, d.department +FROM employees AS e, departments AS d +WHERE e.dept_id = d.dept_id; +``` + +In this example, `employees` and `departments` tables are termed as `e` and `d` respectively. + +That's it! Remember that `FROM` is not limited only to `SELECT`. It is applicable to `UPDATE` and `DELETE` operations as well. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/101-insert.md b/src/data/roadmaps/sql/content/103-dml/101-insert.md new file mode 100644 index 000000000..0f062163e --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/101-insert.md @@ -0,0 +1,48 @@ +# INSERT + +The "INSERT" statement is used to add new rows of data to a table in a database. There are two main forms of the INSERT command: `INSERT INTO` which, if columns are not named, expects a full set of columns, and `INSERT INTO table_name (column1, column2, ...)` where only named columns will be filled with data. + +## Usage + +1. **Insert full set of columns:** + +Code example: + +```sql +INSERT INTO table_name +VALUES (value1, value2, ..., valueN); +``` + +In the example above, you need to provide values for all columns available in the table. + +2. **Selectively insert data:** + +Code example: + +```sql +INSERT INTO table_name (column1, column2, ..., columnN) +VALUES (value1, value2, ..., valueN); +``` + +Here, you only provide values for certain columns of the table. Other columns will take on their default values (if any). + +3. **Insert data from another table:** + +Another useful form of the `INSERT` command is `INSERT INTO SELECT`, which allows you to copy data from one table and add it into another table. + +Code example: + +```sql +INSERT INTO table1 (column1, column2, ... , columnN) +SELECT column1, column2, ... , columnN +FROM table2 +WHERE condition; +``` + +In this scenario, `table2` should already have the data we need and the WHERE clause can be used to select only those rows that satisfy certain conditions. + +> Note: The crucial point is that your columns in both SELECT and INSERT INTO command must be in same order and their datatypes must be compatible. +> +> Kindly ensure that database table has enough space to hold inserted data, else it will resulting in OVERFLOW error. + +**Note**: Always make sure to provide correct and compatible data types for the columns. The SQL engine won't allow you to add data that doesn't match the column's declared data type. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/102-update.md b/src/data/roadmaps/sql/content/103-dml/102-update.md new file mode 100644 index 000000000..fac5dfb9b --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/102-update.md @@ -0,0 +1,53 @@ +# UPDATE + +The `UPDATE` command in SQL is used to modify the existing records in a table. This command is useful when you need to update existing data within a database. + +Here are important points to remember before updating records in SQL: + +- The `WHERE` clause in the `UPDATE` statement specifies which records to modify. If you omit the `WHERE` clause, all records in the table will be updated! + +- Be careful when updating records in SQL. If you inadvertently run an `UPDATE` statement without a `WHERE` clause, you will rewrite all the data in the table. + +## SQL UPDATE Syntax + +Here is a basic syntax of SQL UPDATE command: + +```sql +UPDATE table_name +SET column1 = value1, column2 = value2...., columnN = valueN +WHERE [condition]; +``` + +In this syntax: + +- `table_name`: Specifies the table where you want to update records. +- `SET`: This keyword is used to set the column values. +- `column1, column2... columnN`: These are the columns of the table that you want to change. +- `value1, value2... valueN`: These are the new values that you want to assign for your columns. +- `WHERE`: This clause specifies which records need to be updated. It selects records based on one or more conditions. + +## SQL UPDATE Example + +Let's assume we have the following `Students` table: + +| StudentID | FirstName | LastName | Age | +|-----------|-----------|----------|-----| +| 1 | John | Doe | 20 | +| 2 | Jane | Smith | 22 | +| 3 | Bob | Johnson | 23 | + +And we want to update the `Age` of the student with `StudentID` as 2. We can use the `UPDATE` command as follows: + +```sql +UPDATE Students +SET Age = 23 +WHERE StudentID = 2; +``` + +After executing the above SQL command, the `Age` of the student with `StudentID` 2 will be updated to 23. + +| StudentID | FirstName | LastName | Age | +|-----------|-----------|----------|-----| +| 1 | John | Doe | 20 | +| 2 | Jane | Smith | 23 | +| 3 | Bob | Johnson | 23 | \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/102-where.md b/src/data/roadmaps/sql/content/103-dml/102-where.md new file mode 100644 index 000000000..0a2c08c9a --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/102-where.md @@ -0,0 +1,29 @@ +# WHERE + +SQL provides a WHERE clause that is basically used to filter the records. If the condition specified in the WHERE clause satisfies, then only it returns the specific value from the table. You should use the WHERE clause to filter the records and fetching only the necessary records. + +The WHERE clause is not only used in SELECT statement, but it is also used in UPDATE, DELETE statement, etc., which we will learn in subsequent chapters. + +An example of its implementation is: + +```sql +SELECT * FROM Students WHERE Age>10; +``` + +In this example, the statement selects all fields from the 'Students' table where the 'Age' field value is greater than 10. + +WHERE clause can be combined with AND, OR, and NOT operators. Here's an example: + +```sql +SELECT * FROM Students WHERE Age > 10 AND Gender = 'Female'; +``` + +In this example, the statement selects all fields from 'Students' table where the 'Age' field value is greater than 10 and the 'Gender' is Female. + +The syntax generally looks like this: + +```sql +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/103-delete.md b/src/data/roadmaps/sql/content/103-dml/103-delete.md new file mode 100644 index 000000000..731bb9add --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/103-delete.md @@ -0,0 +1,37 @@ +# DELETE + +The DELETE statement is used to delete existing records in a table. This is a straightforward process, but care must be taken because the DELETE statement is destructive and cannot be undone by default. + +## Syntax + +The basic syntax of a DELETE query with WHERE clause in SQL is as follows: +```sql +DELETE FROM table_name [WHERE condition] +``` + +- `table_name`: Specifies the table where you want to delete data. +- `WHERE condition`: It is optional. You can use the WHERE clause with a DELETE query to delete the selected rows, otherwise all the records would be deleted. + +## Examples + +1. **DELETE ALL Rows** + +Deletes all rows from a table named 'students'. +```sql +DELETE FROM students; +``` + +2. **DELETE Specified Rows** + +Deletes the student whose student_id is '1001' from the 'students' table. +```sql +DELETE FROM students WHERE student_id = '1001'; +``` + +**Caution:** Be very careful when using the DELETE statement. If you omit the WHERE clause, all records will be deleted! + +## Multi-table deletions + +Some database systems allow for deleting from multiple tables in a single DELETE statement. This is database-specific and beyond the scope of the basic SQL DELETE command. + +Remember, always make sure to have a backup and confirm you're deleting the correct data before running a DELETE command, especially in production environments. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/103-order-by.md b/src/data/roadmaps/sql/content/103-dml/103-order-by.md new file mode 100644 index 000000000..8611dda4f --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/103-order-by.md @@ -0,0 +1,55 @@ +# ORDER BY + +The `ORDER BY` clause in SQL is used to sort the result-set from a SELECT statement in ascending or descending order. It sorts the records in ascending order by default. If you want to sort the records in descending order, you have to use the `DESC` keyword. + +## Syntax for Ascending Order: +```sql +SELECT column1, column2, ... +FROM table_name +ORDER BY column1, column2, ... ASC; +``` +Here, `ASC` is used for ascending order. If you use `ORDER BY` without `ASC` or `DESC`, `ASC` is used by default. + +## Syntax for Descending Order: +```sql +SELECT column1, column2, ... +FROM table_name +ORDER BY column1, column2, ... DESC; +``` +Here, `DESC` is used for descending order. + +## Usage Example + +Consider the following `Customers` table: + +| ID | NAME | AGE | ADDRESS | SALARY | +|----|-------|-----|-----------|--------| +| 1 | Ramesh| 32 | Ahmedabad | 2000.0 | +| 2 | Khilan| 25 | Delhi | 1500.0 | +| 3 | kaushik | 23 | Kota | 2000.0 | +| 4 | Chaitali | 25 | Mumbai | 6500.0 | +| 5 | Hardik | 27 | Bhopal | 8500.0 | +| 6 | Komal | 22 | MP | 4500.0 | + +**Example 1 - Ascending Order:** + +Sort the table by the `NAME` column in ascending order: +```sql +SELECT * FROM Customers +ORDER BY NAME ASC; +``` +**Example 2 - Descending Order:** + +Sort the table by the `SALARY` column in descending order: +```sql +SELECT * FROM Customers +ORDER BY SALARY DESC; +``` +**Example 3 - Multiple Columns:** + +You can also sort by multiple columns. Sort the table by the `AGE` column in ascending order and then `SALARY` in descending order: +```sql +SELECT * FROM Customers +ORDER BY AGE ASC, SALARY DESC; +``` +In this instance, the `ORDER BY` clause first sorts the `Customers` table by the `AGE` column and then sorts the sorted result further by the `SALARY` column. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/104-group-by.md b/src/data/roadmaps/sql/content/103-dml/104-group-by.md new file mode 100644 index 000000000..80dc7757b --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/104-group-by.md @@ -0,0 +1,68 @@ +# GROUP BY + +"Group By" is a clause in SQL that is used to arrange identical data into groups. This clause comes under the category of Group Functions, alongside the likes of Count, Sum, Average, etc. + +The syntax for 'Group by' is: + +```sql +SELECT column1, column2 +FROM table_name +GROUP BY column1, column2; +``` + +Here, column1, column2, are the names of the columns based on which we want to group the results. + +## Example: + +Assume we have a "Sales" table. This table has three columns: ID, Item, and Amount. + +```sql +ID Item Amount +--- ------ ------ +1 A 150 +2 B 200 +3 A 100 +4 B 50 +5 A 200 +6 A 100 +7 B 150 +``` + +Execute the following SQL statement... + +```sql +SELECT Item, SUM(Amount) +FROM Sales +GROUP BY Item; +``` + +This will concatenate, or "group", all items that are the same into one row, applying the SUM() function on their respective Amounts. The output will then be: + +```sql +Item SUM(Amount) +------ ---------- +A 550 +B 400 +``` + +## Group By with Having Clause + +The Group By clause can also be used with the Having keyword. The Having keyword allows you to filter the results of the group function. + +For example: + +```sql +SELECT Item, SUM(Amount) +FROM Sales +GROUP BY Item +HAVING SUM(Amount) > 150; +``` + +This will return all grouped items where the total amount is more than 150. Hence, the result will be: + +```sql +Item SUM(Amount) +------ ---------- +A 550 +B 400 +``` \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/105-having.md b/src/data/roadmaps/sql/content/103-dml/105-having.md new file mode 100644 index 000000000..59eb1bdb9 --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/105-having.md @@ -0,0 +1,44 @@ +# HAVING + +`HAVING` is a clause in SQL that allows you to filter result sets in a `GROUP BY` clause. It is used to mention conditions on the groups being selected. In other words, `HAVING` is mainly used with the `GROUP BY` clause to filter the results that a `GROUP BY` returns. + +It’s similar to a `WHERE` clause, but operates on the results of a grouping. The `WHERE` clause places conditions on the selected columns, whereas the `HAVING` clause places conditions on groups created by the `GROUP BY` clause. + +## Syntax + +The basic syntax is as follows: +```sql +SELECT column_name, function(column_name) +FROM table_name +WHERE condition +GROUP BY column_name +HAVING function(column_name) condition value; +``` + +## Example + +Suppose we have a `Sales` table with the following data: + +| SaleID | Product | Quantity | +|--------|---------|----------| +| 1 | A | 30 | +| 2 | B | 20 | +| 3 | A | 100 | +| 4 | B | 50 | +| 5 | C | 60 | +| 6 | A | 70 | + +And we want to find products which have total quantity sold more than 100. We can use the `HAVING` clause as follows: + +```sql +SELECT Product, SUM(Quantity) as TotalQuantity +FROM Sales +GROUP BY Product +HAVING TotalQuantity > 100; +``` + +In this query, + +- `GROUP BY Product` would group the sales figures by Product. +- `SUM(Quantity)` would calculate total quantity sold for each product. +- `HAVING TotalQuantity > 100` would filter out the groups which have total quantity sold less than or equal to 100.- \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/106-joins.md b/src/data/roadmaps/sql/content/103-dml/106-joins.md new file mode 100644 index 000000000..00cbd89a2 --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/106-joins.md @@ -0,0 +1,50 @@ +# JOINs + +SQL Joins are used to retrieve data from two or more data tables, based on a related column between them. The key types of JOINs include: + +1. INNER JOIN: This type of join returns records with matching values in both tables. + +```sql +SELECT table1.column1, table2.column2... +FROM table1 +INNER JOIN table2 +ON table1.matching_column = table2.matching_column; +``` +2. LEFT (OUTER) JOIN: Returns all records from the left table, and matched records from the right table. + +```sql +SELECT table1.column1, table2.column2... +FROM table1 +LEFT JOIN table2 +ON table1.matching_column = table2.matching_column; +``` +3. RIGHT (OUTER) JOIN: Returns all records from the right table, and matched records from the left table. + +```sql +SELECT table1.column1, table2.column2... +FROM table1 +RIGHT JOIN table2 +ON table1.matching_column = table2.matching_column; +``` +4. FULL (OUTER) JOIN: Returns all records when either a match is found in either left (table1) or right (table2) table records. + +```sql +SELECT table1.column1, table2.column2... +FROM table1 +FULL JOIN table2 +ON table1.matching_column = table2.matching_column; +``` +5. SELF JOIN: A self join is a join in which a table is joined with itself. + +```sql +SELECT a.column_name, b.column_name... +FROM table_name AS a, table_name AS b +WHERE condition; +``` +6. CARTESIAN JOIN: If WHERE clause is omitted, the join operation produces a Cartesian product of the tables involved in the join. The size of a Cartesian product result set is the number of rows in the first table multiplied by the number of rows in the second table. + +```sql +SELECT table1.column1, table2.column2... +FROM table1, table2; +``` +Each type of JOIN allows for the retrieval of data in different situations, making them flexible and versatile for different SQL queries. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/103-dml/index.md b/src/data/roadmaps/sql/content/103-dml/index.md new file mode 100644 index 000000000..ad68436ca --- /dev/null +++ b/src/data/roadmaps/sql/content/103-dml/index.md @@ -0,0 +1,41 @@ +# Data Manipulation Language (DML) + +*DML* is a subcategory of `SQL` which stands for _Data Manipulation Language_. The purpose of DML is to insert, retrieve, update and delete data from the database. With this, we can perform operations on existing records. + +DML contains four commands which are: + +1. **INSERT INTO** - This command is used to insert new rows (records) into a table. + +Example: + +```sql +INSERT INTO table_name ( column1, column2, column3, ... ) +VALUES ( value1, value2, value3, ... ) +``` + +2. **SELECT** - This command is used to select data from a database. The data returned is stored in a result table, called the result-set. + +Example: + +```sql +SELECT column1, column2, ... +FROM table_name +``` + +3. **UPDATE** - This command is used to modify the existing rows in a table. + +Example: + +```sql +UPDATE table_name +SET column1 = value1, column2 = value2, ... +WHERE condition; +``` + +4. **DELETE FROM** - This command is used to delete existing rows (records) from a table. + +Example: + +```sql +DELETE FROM table_name WHERE condition; +``` \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/100-select.md b/src/data/roadmaps/sql/content/104-aggregate-queries/100-select.md new file mode 100644 index 000000000..e0fd619ff --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/100-select.md @@ -0,0 +1,73 @@ +# SELECT + +`SELECT` is one of the most widely used commands in SQL. This command is used to select data from a database. The data returned is stored in a results table, also called the result-set. + +## Syntax + +The simplest way to use the `SELECT` statement is to return all columns from a table. This can be done with the following syntax: + +```sql +SELECT * FROM table_name; +``` + +This will return all fields (columns) of all records (rows) from the table. + +If you want to select just certain columns, you can specify them by name, separated by commas: + +```sql +SELECT column_name1, column_name2 FROM table_name; +``` + +## SELECT DISTINCT + +The `SELECT DISTINCT` statement is used to return only unique values in the output. It can be used to eliminate duplicate values in the returned data. + +```sql +SELECT DISTINCT column_name FROM table_name; +``` + +## WHERE Clause + +The `WHERE` clause is used to filter records. The `WHERE` clause is used to extract only those records that fulfill a specified condition. + +```sql +SELECT column_name FROM table_name WHERE condition; +``` + +## ORDER BY + +The `ORDER BY` keyword is used to sort the result-set in ascending or descending order. The `ORDER BY` keyword sorts the records in ascending order by default. If you want to sort the records in descending order, you can use the `DESC` keyword. + +```sql +SELECT column_name FROM table_name ORDER BY column_name ASC|DESC; +``` + +## Aggregate Functions + +Aggregate functions in SQL are functions where the values of multiple rows are grouped together to form a single value of more significant meaning, such as a list, a set, or a sum. Some examples include `SUM()`, `COUNT()`, `MIN()`, `MAX()`, and `AVG()`. + +```sql +SELECT COUNT(column_name) FROM table_name WHERE condition; +SELECT AVG(column_name) FROM table_name WHERE condition; +SELECT SUM(column_name) FROM table_name WHERE condition; +SELECT MIN(column_name) FROM table_name WHERE condition; +SELECT MAX(column_name) FROM table_name WHERE condition; +``` + +## GROUP BY + +The `GROUP BY` statement is often used with aggregate functions (`COUNT`, `MAX`, `MIN`, `SUM`, `AVG`) to group the result-set by one or more columns. + +```sql +SELECT column_name1, COUNT(column_name2) FROM table_name WHERE condition GROUP BY column_name1 ORDER BY COUNT(column_name2) DESC; +``` + +## HAVING Clause + +The `HAVING` clause was added to SQL because the `WHERE` keyword could not be used with aggregate functions. It works like the WHERE clause but on grouped records. + +```sql +SELECT column_name, COUNT(column_name) FROM table_name GROUP BY column_name HAVING COUNT(column_name) > value; +``` + +The above are the most common uses of the `SELECT` keyword in SQL. There are other keywords and functions you can use to manipulate the data as well. These will give you a good start on using `SELECT` in your SQL queries. diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/101-group-by.md b/src/data/roadmaps/sql/content/104-aggregate-queries/101-group-by.md new file mode 100644 index 000000000..b9be5b419 --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/101-group-by.md @@ -0,0 +1,57 @@ +# GROUP BY + +**Group By** is an SQL clause that arranges identical data into groups. It is often used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the result-set by one or multiple columns. + +## Syntax: + +```sql +SELECT column1, column2, ..., aggregate_function(column_name) +FROM table_name +WHERE condition +GROUP BY column1, column2, ...; +``` + +## Explanation: + +- **column1, column2**, these columns are not under the aggregate function or any operation. They will be used to group the data. +- **aggregate_function(column_name)**, Aggregate functions will apply on the group of the column_name specified, not individual rows. +- The **WHERE** clause is optional. It adds conditions to select which rows will be grouped. + +## Examples: + +Here's an example of the **Group By** clause in action. Given is a table **Sales**: + +| order_id | product_id | qty | +|----------|------------|-----| +| 1 | 1001 | 20 | +| 2 | 1002 | 10 | +| 3 | 1003 | 50 | +| 4 | 1001 | 10 | +| 5 | 1002 | 20 | +| 6 | 1003 | 50 | + +## Example 1: +```sql +SELECT product_id, SUM(qty) +FROM SALES +GROUP BY product_id; +``` + +The result will be: + +|product_id | SUM(qty) +|-----------|----------| +| 1001 | 30 | +| 1002 | 30 | +| 1003 | 100 | + +## Example 2: + +You can perform group by operation on multiple columns. In the below example, 'product_id' and 'order_id' are used to group the data. +```sql +SELECT product_id, order_id, SUM(qty) +FROM SALES +GROUP BY product_id, order_id; +``` + +**Group By** clause can be used with **HAVING** clause to add a condition on grouped data. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/101-sum.md b/src/data/roadmaps/sql/content/104-aggregate-queries/101-sum.md new file mode 100644 index 000000000..cc6983bd8 --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/101-sum.md @@ -0,0 +1,58 @@ +# SUM + +The `SUM()` function in SQL is used to calculate the sum of a column. This function allows you to add up a column of numbers in an SQL table. + +The syntax for SUM is as follows: + +```sql +SELECT SUM(column_name) FROM table_name; +``` + +Where `column_name` is the name of the column you want to calculate the sum of, and `table_name` is the name of the table where the column is. + +For example, consider the following `ORDER` table: + +``` +| OrderID | Company | Quantity | +|-------------|-----------|----------| +| 1 | A | 30 | +| 2 | B | 15 | +| 3 | A | 20 | +``` + +If you want to find the total quantity, you can use `SUM()`: + +```sql +SELECT SUM(Quantity) AS TotalQuantity FROM Order; +``` + +Output will be: + +``` +| TotalQuantity | +|----------------| +| 65 | +``` + +**Note:** The `SUM()` function skips NULL values. + +One of the common use cases of `SUM()` function is in conjunction with `GROUP BY` to get the sum for each group of rows. + +Example: + +```sql +SELECT Company, SUM(Quantity) AS TotalQuantity +FROM Order +GROUP BY Company; +``` + +This will give us the sum of `Quantity` for each `Company` in the `Order` table. + +``` +| Company | TotalQuantity | +|-----------|----------------| +| A | 50 | +| B | 15 | +``` + +Notably, in all databases, including MySQL, PostgreSQL, and SQLite, the `SUM()` function operates the same way. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/102-count.md b/src/data/roadmaps/sql/content/104-aggregate-queries/102-count.md new file mode 100644 index 000000000..b6188d7b7 --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/102-count.md @@ -0,0 +1,29 @@ +# COUNT + +`COUNT` is a SQL function that returns the number of rows that match a specified criteria. Essentially, `COUNT` function is used when you need to know the count of a record in a certain table's column. + +There are two types of count function; `COUNT(*)` and `COUNT(column)`. + +- `COUNT(*)` counts all the rows in the target table whether columns contain null values or not. + +```sql +SELECT COUNT(*) FROM table_name; +``` + +- `COUNT(column)` counts the rows in the column of a table excluding null. + +```sql +SELECT COUNT(column_name) FROM table_name; +``` + +You may also use `COUNT()` in conjunction with `GROUP BY` to return the count of rows within each group. + +A typical example would be: + +```sql +SELECT column_name, COUNT(*) FROM table_name GROUP BY column_name; +``` + +Here, `column_name` is the name of the column based on which the rows will be grouped. This query will return the count of rows in each group of `column_name`. + +By understanding how to use the `COUNT()` function, you can extract more meaningful data from your tables, and perform analytics and generate reports based on the counts of certain attributes in your database. diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/102-having.md b/src/data/roadmaps/sql/content/104-aggregate-queries/102-having.md new file mode 100644 index 000000000..caa5b1c3f --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/102-having.md @@ -0,0 +1,51 @@ +# HAVING + +The `HAVING` clause is used in combination with the `GROUP BY` clause to filter the results of `GROUP BY`. It is used to mention conditions on the group functions, like `SUM`, `COUNT`, `AVG`, `MAX` or `MIN`. + +It's important to note that where `WHERE` clause introduces conditions on individual rows, `HAVING` introduces conditions on groups created by the `GROUP BY` clause. + +Also note, `HAVING` applies to summarized group records, whereas `WHERE` applies to individual records. + +Syntax: + +```sql +SELECT column_name(s) +FROM table_name +WHERE condition +GROUP BY column_name(s) +HAVING condition +ORDER BY column_name(s); +``` + +## Example + +Consider this "Orders" table: + +| OrderID | Customer | Amount | +|---------|----------|--------| +| 1 | John | 1000 | +| 2 | Mary | 1500 | +| 3 | John | 2000 | +| 4 | Jane | 1000 | +| 5 | Mary | 2000 | +| 6 | John | 3000 | +| 7 | Jane | 2000 | +| 8 | Mary | 2500 | + +For instance, if you wanted to find customers who have spent more than $3000 in total, you might use the `HAVING` clause as follows: + +```sql +SELECT Customer, SUM(Amount) +FROM Orders +GROUP BY Customer +HAVING SUM(Amount) > 3000; +``` + +As a result, the query returns: + +| Customer | SUM(Amount) | +|----------|-------------| +| John | 6000 | +| Mary | 6000 | + +In this case, the `HAVING` clause filters out all Customers with a total `Amount` less than $3000. Only John and Mary have the total sum of `Amount` more than or equal to $3000. Thus, only these records satisfy the `HAVING` clause and are included in the result. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/103-avg.md b/src/data/roadmaps/sql/content/104-aggregate-queries/103-avg.md new file mode 100644 index 000000000..3ea67b90b --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/103-avg.md @@ -0,0 +1,40 @@ +# AVG + +The `AVG()` function in SQL is an aggregate function that returns the average value of a numeric column. It calculates the sum of values in a column and then divides it by the count of those values. + +Syntax: +``` +SELECT AVG(column_name) +FROM table_name; +``` +This statement will return the average value of the specified column. + +## Example Usage of AVG: + +Consider the following table `Orders`: + +| OrderID | CustomerID | Quantity | +|---------|------------|----------| +| 1 | A | 30 | +| 2 | A | 40 | +| 3 | B | 20 | +| 4 | B | 60 | +| 5 | C | 50 | +| 6 | C | 10 | + +Let's calculate the average quantity in the `Orders` table: +```sql +SELECT AVG(Quantity) AS AvgQuantity +FROM Orders; +``` +The result is 35. This value is the average of all `Quantity` values in the table. + +It's also possible to group the average function by one or more columns. For example, to find the average quantity of order per customer, we can write: +```sql +SELECT CustomerID, AVG(Quantity) as AvgQuantity +FROM Orders +GROUP BY CustomerID; +``` +It will calculate the average quantity for each customer and display the result along with the associated customer's ID. + +> Note: The `AVG()` function works only with numeric data types (`INT`, `FLOAT`, `DECIMAL`, etc.). It will return an error if used with non-numeric data types. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/104-min.md b/src/data/roadmaps/sql/content/104-aggregate-queries/104-min.md new file mode 100644 index 000000000..f89c7c8e4 --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/104-min.md @@ -0,0 +1,57 @@ +# MIN + +`MIN` is an SQL aggregate function used to return the smallest value in a selected column. It is useful in querying tables where users want to identify the smallest or least available value in datasets. `MIN` ignores any null values in the dataset. + +Syntax: + +```sql +SELECT MIN(column_name) +FROM table_name +WHERE condition; +``` + +In the case where `column_name` belongs to a numeric data type (Integers, Float, etc.), `MIN` returns the smallest numeric value in the column. + +If `column_name` belongs to datetime types (Date, Time, etc.), `MIN` returns the earliest date or time. + +If `column_name` belongs to string types (Char, Text, etc.), `MIN` returns the lowest value in lexicographic order (similar to alphabetic order). + +## Examples: + +Consider a table, named `Orders`, with the following layout: + +| OrderID | CustomerID | OrderDate | +|---------|-------------|------------| +| 1 | C01 | 2020-10-10 | +| 2 | C02 | 2020-09-05 | +| 3 | C01 | 2020-08-21 | + +1. To find the earliest order date in the `Orders` table, the `MIN` function is used in the following way: + +```sql +SELECT MIN(OrderDate) AS EarliestOrder +FROM Orders; +``` + +The result of this query will be `2020-08-21`. + +2. Suppose we have a Prices table with items and their prices. To find the lowest price, use: + +```sql +SELECT MIN(price) AS LowestPrice +FROM Prices; +``` + +This query will return the smallest value in the price column. + +One important usage is when it is used along with the `GROUP BY` clause to find the minimum value in each group. + +Example, to find the earliest order date for each customer: + +```sql +SELECT CustomerID, MIN(OrderDate) AS EarliestOrder +FROM Orders +GROUP BY CustomerID; +``` + +This query will return the earliest order date for each customer. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/105-max.md b/src/data/roadmaps/sql/content/104-aggregate-queries/105-max.md new file mode 100644 index 000000000..f744089f2 --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/105-max.md @@ -0,0 +1,37 @@ +# MAX + +The `MAX()` function in SQL is used to return the maximum value of an expression in a SELECT statement. + +It can be used for numeric, character, and datetime column data types. If there are null values, then they are not considered for comparison. + +## Syntax + +```sql +SELECT MAX(column_name) +FROM table_name +WHERE condition; +``` + +In this syntax, the `column_name` argument is the column in the `table_name` that you wish to find the maximum value of. + +## Example + +Consider the following Employee table: + +| ID | NAME | SALARY | +|----|----------|--------| +| 1 | John | 1000 | +| 2 | Robert | 2000 | +| 3 | Jim | 3000 | +| 4 | Jessica | 2500 | + +To find the highest salary amongst all the employees, you would use the `MAX()` function as follows: + +```sql +SELECT MAX(SALARY) AS "Highest Salary" +FROM Employee; +``` + +The above SQL returns `3000` as it’s the highest salary in the Employee table. + +Warning: SQL `MAX()` function will only return a single row as a result. If multiple rows hold the highest value and if you want to get all these rows, you should not use `MAX()`. A better option would be sorting the column and then `LIMIT` the result just to the first row. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/104-aggregate-queries/index.md b/src/data/roadmaps/sql/content/104-aggregate-queries/index.md new file mode 100644 index 000000000..ef23ec87a --- /dev/null +++ b/src/data/roadmaps/sql/content/104-aggregate-queries/index.md @@ -0,0 +1,80 @@ +# Aggregate Queries + +SQL aggregate functions are inbuilt functions that are used to perform some calculation on the data and return a single value. This is why they form the basis for "aggregate queries". These functions operate on a set of rows and return a single summarized result. + +## Common Aggregate Functions + +**1. COUNT()** + +Counts the number of rows. + ``` + SELECT COUNT(column_name) + FROM table_name + WHERE condition; + ``` + +**2. SUM()** + +Returns the sum of a numeric column. + + ``` + SELECT SUM(column_name) + FROM table_name + WHERE condition; + ``` + +**3. AVG()** + +Returns the average value of a numeric column. + ``` + SELECT AVG(column_name) + FROM table_name + WHERE condition; + ``` + +**4. MIN()** + +Returns the smallest value of the selected column. + ``` + SELECT MIN(column_name) + FROM table_name + WHERE condition; + ``` + +**5. MAX()** + +Returns the largest value of the selected column. + ``` + SELECT MAX(column_name) + FROM table_name + WHERE condition; + ``` + +These functions ignore NULL values. + +## GROUP BY and HAVING Clauses + +To separate the results into groups of accumulated data, you can use the GROUP BY clause. + +``` +SELECT column1, aggregate_function(column2) +FROM table +GROUP BY column1; +``` + +"A group" is represented by ROW(s) that have the same value in the specific column(s). The GROUP BY clause can be used in a SELECT statement to collect data across multiple records and group by some columns. + +The HAVING clause is used with the GROUP BY clause, it applies to summarized group records, unlike the 'where' clause. It was added to SQL because the WHERE keyword could not be used with aggregate functions. + +```sql +SELECT column1, aggregate_function(column2) +FROM table +GROUP BY column1 +HAVING conditions; +``` + +## Conclusion + +Aggregate queries are simply a way of summarizing information in your database. Although they are a powerful tool, they can become complex very quickly, especially if you start nesting them together or combining multiple aggregate functions in a single query. + +> Note: The real power of aggregate functions comes when you combine them with the WHERE or HAVING clause, allowing you to filter the data that you are summarizing. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/105-data-constraints/100-primary-key.md b/src/data/roadmaps/sql/content/105-data-constraints/100-primary-key.md new file mode 100644 index 000000000..27449ce18 --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/100-primary-key.md @@ -0,0 +1,52 @@ +# Primary Key + +A primary key is a special relational database table field (or combination of fields) designated to uniquely identify all table records. + +A primary key's main features are: + +- It must contain a unique value for each row of data. +- It cannot contain null values. + +## Usage of Primary Key + +You define a primary key for a table using the `PRIMARY KEY` constraint. A table can have only one primary key. You can define a primary key in SQL when you create or modify a table. + +## Create Table With Primary Key + +In SQL, you can create a table with a primary key by using `CREATE TABLE` syntax. + +```sql +CREATE TABLE Employees ( + ID INT PRIMARY KEY, + NAME TEXT, + AGE INT, + ADDRESS CHAR(50) +); +``` + +In this example, `ID` is the primary key which must consist of unique values and can't be null. + +## Modify Table to Add Primary Key + +If you want to add a primary key to an existing table, you can use `ALTER TABLE` syntax. + +```sql +ALTER TABLE Employees +ADD PRIMARY KEY (ID); +``` + +This will add a primary key to `ID` column in the `Employees` table. + +## Composite Primary Key + +We can also use multiple columns to define a primary key. Such key is known as composite key. + +```sql +CREATE TABLE Customers ( + CustomerID INT, + StoreID INT, + CONSTRAINT pk_CustomerID_StoreID PRIMARY KEY (CustomerID,StoreID) +); +``` + +In this case, each combination of `CustomerID` and `StoreID` must be unique across the whole table. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/105-data-constraints/101-foreign-key.md b/src/data/roadmaps/sql/content/105-data-constraints/101-foreign-key.md new file mode 100644 index 000000000..acc557947 --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/101-foreign-key.md @@ -0,0 +1,37 @@ +# Foreign Key + +A foreign key is a key used to link two tables together. It is a field (or collection of fields) in one table that refers to the primary key in another table. The table with the foreign key is called the child table, and the one with the primary key is called the referenced or parent table. + +## Basic Syntax + +The SQL used to add a foreign key constraint is: + +```sql +ALTER TABLE child_table +ADD FOREIGN KEY (fk_column) +REFERENCES parent_table (parent_key_column) +``` + +Where: +- `child_table` is the table where you want to add the foreign key +- `fk_column` is the field in the child table that you want to use as foreign key +- `parent_table` is the table being referenced by the foreign key +- `parent_key_column` is the column in `parent_table` that `fk_column` points to + +## Example + +Suppose we have two tables, `Orders` and `Customers` where `Orders` table has a column `customer_id` that should point to a Customer. If `Customers` has a `customer_id` column as the primary key then you can create a foreign key as follows + +```sql +ALTER TABLE Orders +ADD FOREIGN KEY (customer_id) +REFERENCES Customers (customer_id); +``` + +This means that for every row in `Orders`, the `customer_id` value must match a value in the `Customers` table, ensuring data integrity. + +## Note + +Please note that MySQL requires you to have the foreign key columns be indexed for performance reasons. If they aren't indexed already, the `FOREIGN KEY` constraint will implicitly index them for you. Also, a significant thing to note is, InnoDB does not support the 'foreign key check' in CREATE TABLE statements, instead, you must use ALTER TABLE after the table has been created. + +Not all database systems support all types of keys, and different systems support different syntax for them. The examples above are in SQL syntax, which is supported by most databases. diff --git a/src/data/roadmaps/sql/content/105-data-constraints/102-unique.md b/src/data/roadmaps/sql/content/105-data-constraints/102-unique.md new file mode 100644 index 000000000..74db5f63e --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/102-unique.md @@ -0,0 +1,54 @@ +# Unique + +The `UNIQUE` constraint ensures that all values in a column are different; that is, each value in the column should occur only once. + +Both the `UNIQUE` and `PRIMARY KEY` constraints provide a guarantee for uniqueness for a column or set of columns. However, a primary key can contain only `NULL`, and each table can have only one primary key. On the other hand, a `UNIQUE` constraint allows for one `NULL` value, and a table can have multiple `UNIQUE` constraints. + +## Syntax +```sql +CREATE TABLE table_name ( + column1 data_type UNIQUE, + column2 data_type, + column3 data_type, + .... +); +``` + +Here, `UNIQUE` is the constraint's name, whereas `column1` and `data_type` refer to the column and data type for which we're setting the constraint, respectively. + +## Example + +Suppose, for instance, we are creating a table named "Employees". We want the "Email" column to contain only unique values to avoid any duplication in email addresses. + +Here's how we can impose a `UNIQUE` constraint on the "Email" column: + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar (255) NOT NULL, + Email varchar (255) UNIQUE +); +``` + +In this SQL command, we are telling the SQL server that the "Email" column cannot have the same value in two or more rows. + +## Adding a Unique Constraint to an Existing Table + +To add a `UNIQUE` constraint to an existing table, you would use the `ALTER TABLE` command. Here is the syntax: + +```sql +ALTER TABLE table_name +ADD UNIQUE (column1, column2, ...); +``` +Here, `table_name` is the name of the table on which we're defining the constraint, and `column1`, `column2`, etc., are the names of the columns included in the constraint. + +## Dropping a Unique Constraint + +The `ALTER TABLE` command is also used to drop a `UNIQUE` constraint. The syntax to drop a `UNIQUE` constraint is: + +```sql +ALTER TABLE table_name +DROP CONSTRAINT constraint_name; +``` + +Here, `constraint_name` is the name of the `UNIQUE` constraint that you want to drop. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/105-data-constraints/103-not-null.md b/src/data/roadmaps/sql/content/105-data-constraints/103-not-null.md new file mode 100644 index 000000000..f45812c8f --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/103-not-null.md @@ -0,0 +1,40 @@ +# NOT NULL + +The `NOT NULL` constraint in SQL ensures that a column cannot have a NULL value. Thus, every row/record must contain a value for that column. It is a way to enforce certain fields to be mandatory while inserting records or updating records in a table. + +For instance, if you're designing a table for employee data, you might want to ensure that the employee's `id` and `name` are always provided. In this case, you'd use the `NOT NULL` constraint. + +## Creating a table with NOT NULL + +Here's an example of how you would define a `NOT NULL` constraint when creating a table: + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + Address varchar(255) +); +``` + +In this example, the `ID` and `Name` fields are mandatory for each record. + +## Adding NOT NULL to an existing table + +You can also add a `NOT NULL` constraint to an existing table using the `ALTER TABLE` statement. However, make sure there are no NULL values in the column before adding the `NOT NULL` constraint. + +Here's an example: + +```sql +ALTER TABLE Employees +MODIFY Address varchar(255) NOT NULL; +``` + +This command will modify the table `Employees` and set the `Address` column to be `NOT NULL`. + +**Note:** In some SQL systems like PostgreSQL, you use the `ALTER TABLE` command followed by `SET NOT NULL`. + +--- + +Be aware that if you try to insert a record without a value for a `NOT NULL` column, the database will return an error and the operation will fail. +Ensure data compatibility before setting the `NOT NULL` constraint. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/105-data-constraints/104-check.md b/src/data/roadmaps/sql/content/105-data-constraints/104-check.md new file mode 100644 index 000000000..008b0d8ba --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/104-check.md @@ -0,0 +1,64 @@ +# CHECK + +In SQL, `CHECK` is a constraint that limits the value range that can be placed in a column. It enforces domain integrity by limiting the values in a column to meet a certain condition. + +`CHECK` constraint can be used in a column definition when you create or modify a table. + +## Syntax + +To use the `CHECK` constraint, you can follow this syntax: + +```sql +CREATE TABLE table_name ( + column1 datatype CONSTRAINT constraint_name CHECK (condition), + column2 datatype, + ... +); +``` + +If you need to apply the `CHECK` constraint on multiple columns, use the following syntax: + +```sql +CREATE TABLE table_name ( + column1 datatype, + column2 datatype, + ..., + CONSTRAINT constraint_name CHECK (condition) +); +``` + +## Examples + +Here is an example of applying a `CHECK` constraint on a single column: + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Age int, + Salary int CHECK (Salary>0), +); +``` + +Above SQL statement ensures that the salary of all employees in the Employees table must be more than 0. + +Here is an example of applying a `CHECK` constraint on multiple columns: + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Age int, + Salary int, + CONSTRAINT CHK_Person CHECK (Age>=18 AND Salary>=0) +); +``` + +Above SQL ensures that the persons' age must be greater than or equal to 18, and their salary is more than or equal to 0. + +It is also possible to use the `ALTER TABLE` command to add a `CHECK` constraint after the table has been created. + +```sql +ALTER TABLE Employees +ADD CONSTRAINT CHK_EmployeeAge CHECK (Age >= 21 AND Age <= 60); +``` + +Above SQL ensures that the employees' age must be between 21 and 60. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/105-data-constraints/index.md b/src/data/roadmaps/sql/content/105-data-constraints/index.md new file mode 100644 index 000000000..55f812ea8 --- /dev/null +++ b/src/data/roadmaps/sql/content/105-data-constraints/index.md @@ -0,0 +1,93 @@ +# Data Constraints + +Data constraints in SQL are used to specify rules for the data in a table. Constraints are used to limit the type of data that can go into a table. This ensures the accuracy and reliability of the data in the table. + +## Types of SQL Data Constraints + +1. **NOT NULL Constraint**: Ensures that a column cannot have a NULL value. + + For Example: + + ```sql + CREATE TABLE Students ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int + ); + ``` + +2. **UNIQUE Constraint**: Ensures that all values in a column are different. + + For Example: + + ```sql + CREATE TABLE Students ( + ID int NOT NULL UNIQUE, + Name varchar(255) NOT NULL, + Age int + ); + ``` + +3. **PRIMARY KEY Constraint**: Uniquely identifies each record in a database table. Primary keys must contain UNIQUE values. Exactly the same as the UNIQUE constraint but there can be many unique constraints in a table, but only one PRIMARY KEY constraint per table. + + For Example: + + ```sql + CREATE TABLE Students ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + PRIMARY KEY (ID) + ); + ``` + +4. **FOREIGN KEY Constraint**: Prevents actions that would destroy links between tables. A FOREIGN KEY is a field (or collection of fields) in one table that refers to the PRIMARY KEY in another table. + + For Example: + + ```sql + CREATE TABLE Orders ( + OrderID int NOT NULL, + OrderNumber int NOT NULL, + ID int, + PRIMARY KEY (OrderID), + FOREIGN KEY (ID) REFERENCES Students(ID) + ); + ``` + +5. **CHECK Constraint**: The CHECK constraint ensures that all values in a column satisfies certain conditions. + + For Example: + + ```sql + CREATE TABLE Students ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + CHECK (Age>=18) + ); + ``` + +6. **DEFAULT Constraint**: Provides a default value for a column when none is specified. + + For Example: + + ```sql + CREATE TABLE Students ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + City varchar(255) DEFAULT 'Unknown' + ); + ``` + +7. **INDEX Constraint**: Used to create and retrieve data from the database very quickly. + + For Example: + + ```sql + CREATE INDEX idx_name + ON Students (Name); + ``` + + Note: Indexes are not a part of the SQL standard and are not supported by all databases. diff --git a/src/data/roadmaps/sql/content/106-join-queries/100-inner-join.md b/src/data/roadmaps/sql/content/106-join-queries/100-inner-join.md new file mode 100644 index 000000000..d80a2ba1d --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/100-inner-join.md @@ -0,0 +1,58 @@ +# INNER JOIN + +An `INNER JOIN` in SQL is a type of join that returns the records with matching values in both tables. This operation compares each row of the first table with each row of the second table to find all pairs of rows that satisfy the join predicate. + +Few things to consider in case of `INNER JOIN`: + +- It is a default join in SQL. If you mention `JOIN` in your query without specifying the type, SQL considers it as an `INNER JOIN`. +- It returns only the matching rows from both the tables. +- If there is no match, the returned is an empty result. + +## Syntax + +Here is the syntax for an SQL `INNER JOIN`: + +```sql +SELECT column_name(s) +FROM table1 +INNER JOIN table2 +ON table1.column_name = table2.column_name; +``` + +The `INNER JOIN` keyword selects records that have matching values in both tables. + +## Example + +Consider two tables: + +**Table1: `Orders`** + +|OrderID|CustomerID|OrderAmount| +|-------|----------|-----------| +|1 |100 |30 | +|2 |101 |40 | +|3 |102 |50 | + +**Table2: `Customers`** + +|CustomerID|Name |Country | +|----------|--------|---------| +|100 |Ana |Germany | +|101 |Ben |USA | +|103 |Charlie |Australia| + +Now, if you want to select all orders, and any matching customer information: + +```sql +SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderAmount +FROM Orders +INNER JOIN Customers +ON Orders.CustomerID = Customers.CustomerID; +``` + +This would produce the following result: + +|OrderID|Name|OrderAmount| +|-------|----|-----------| +|1 |Ana |30 | +|2 |Ben |40 | diff --git a/src/data/roadmaps/sql/content/106-join-queries/101-left-join.md b/src/data/roadmaps/sql/content/106-join-queries/101-left-join.md new file mode 100644 index 000000000..6523aba53 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/101-left-join.md @@ -0,0 +1,30 @@ +# LEFT JOIN + +The SQL LEFT JOIN combines rows from two or more tables based on a related column between them and returns all rows from the left table (table1) and the matched rows from the right table (table2). If there is no match, the result is `NULL` on the right side. + +## Syntax +``` +SELECT column_name(s) +FROM table1 +LEFT JOIN table2 +ON table1.column_name = table2.column_name; +``` + +## How SQL LEFT JOIN Works + +The `LEFT JOIN` keyword returns all records from the left table (table1), and the matched records from the right table (table2). The result is `NULL` from the right side, if there is no match. + +![LEFT JOIN Diagram](https://www.w3schools.com/sql/img_leftjoin.gif) + +## SQL LEFT JOIN Example + +Let's assume we have two tables: `Orders` and `Customers`. + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +LEFT JOIN Customers +ON Orders.CustomerID = Customers.CustomerID; +``` + +This SQL statement would return all OrderID and the matching CustomerName. If there is no match, the result is `NULL`. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/106-join-queries/102-right-join.md b/src/data/roadmaps/sql/content/106-join-queries/102-right-join.md new file mode 100644 index 000000000..9db20e1a9 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/102-right-join.md @@ -0,0 +1,63 @@ +# RIGHT JOIN + +The `RIGHT JOIN` keyword returns all records from the right table (table2), and the matched records from the left table (table1). If there is no match, the result is `NULL` on the left side. + +## Syntax + +Below is the common syntax used for writing a `RIGHT JOIN`: + +```sql +SELECT column_name(s) +FROM table1 +RIGHT JOIN table2 +ON table1.column_name = table2.column_name; +``` + +## Example + +Consider two tables: + +**Table "Orders":** + +| OrderID | CustomerID | OrderDate | +|--|--|--| +| 1 | 3 | 2017/11/11 | +| 2 | 1 | 2017/10/23 | +| 3 | 2 | 2017/9/15 | +| 4 | 4 | 2017/9/03 | + +**Table "Customers":** + +| CustomerID | CustomerName | ContactName | Country | +|--|--|--|--| +| 1 | Alfreds Futterkiste | Maria Anders | Germany | +| 2 | Ana Trujillo Emparedados y helados | Ana Trujillo | Mexico | +| 3 | Antonio Moreno Taquería | Antonio Moreno | Mexico | +| 5 | Berglunds snabbköp | Christina Berglund | Sweden | + +Now, we want to select all customers and any matching records in orders table. If there is no match, the result is null in order table: + +```sql +SELECT + Customers.CustomerName, + Orders.OrderID +FROM + Orders +RIGHT JOIN + Customers +ON + Orders.CustomerID = Customers.CustomerID; +``` + +**Result:** + +| CustomerName | OrderID | +|--|--| +| Alfreds Futterkiste | 2 | +| Ana Trujillo Emparedados y helados | 3 | +| Antonio Moreno Taquería | 1 | +| Berglunds snabbköp | NULL | +| Around the Horn | NULL | +| Bottom-Dollar Markets | NULL | + +As you can see, the `RIGHT JOIN` keyword returned all the records from the Customers table and all matched records from the Orders table. For those customers who have no orders (like "Berglunds snabbköp"), the result is `NULL`. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/106-join-queries/103-full-outer-join.md b/src/data/roadmaps/sql/content/106-join-queries/103-full-outer-join.md new file mode 100644 index 000000000..354342d39 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/103-full-outer-join.md @@ -0,0 +1,63 @@ +# FULL OUTER JOIN + +A `FULL OUTER JOIN` in SQL is a method to combine rows from two or more tables, based on a related column between them. It returns all rows from the left table (`table1`) and from the right table (`table2`). + +The `FULL OUTER JOIN` keyword combines the results of both left and right outer joins and returns all (matched or unmatched) rows from the tables on both sides of the join clause. + +If there are records in the "Customers" table that do not have matches in the "Orders" table, those will be included. Also, if there are records in the "Orders" table that do not have matches in the "Customers" table, those will be included. + +## Syntax + +``` +SELECT column_name(s) +FROM table1 +FULL OUTER JOIN table2 +ON table1.column_name = table2.column_name; +``` + +## Code Example + +Consider the following two tables: + +**Table1: Customers** + +| ID | Name | +|----|-------| +| 1 | Tom | +| 2 | Lucy | +| 3 | Steve | +| 4 | Dave | + +**Table2: Orders** + +| OrderID | CustomerID | Product | +|---------|------------|----------| +| 1 | 3 | Apple | +| 2 | 3 | Banana | +| 3 | 1 | Orange | +| 4 | 2 | Mango | +| 5 | 7 | Blueberry| + +A `FULL OUTER JOIN` query would look like this: + +``` +SELECT Customers.Name, Orders.Product +FROM Customers +FULL OUTER JOIN Orders +ON Customers.ID = Orders.CustomerID +ORDER BY Customers.Name; +``` + +The result-set will look like this: + +| Name | Product | +|-------|----------| +| Tom | Orange | +| Lucy | Mango | +| Steve | Apple | +| Steve | Banana | +| NULL | Blueberry| +| Dave | NULL | + +This response includes all customers and all orders. If no matching orders exist for a customer, or if no matching customer exists for an order, the missing side will contain NULL. +For example, Dave made no orders (his details in the product column are NULL) and the Blueberry order was made by a non-existing customer (the customer's details are NULL in the name column). \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/106-join-queries/104-self-join.md b/src/data/roadmaps/sql/content/106-join-queries/104-self-join.md new file mode 100644 index 000000000..ecc7b3404 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/104-self-join.md @@ -0,0 +1,44 @@ +# Self Join + +A `SELF JOIN` is a standard SQL operation where a table is joined to itself. This might sound counter-intuitive, but it's actually quite useful in scenarios where comparison operations need to be made within a table. Essentially, it is used to combine rows with other rows in the same table when there's a match based on the condition provided. + +It's important to note that, since it's a join operation on the same table, alias(es) for table(s) must be used to avoid confusion during the join operation. + +## Syntax of a Self Join + +Here is the basic syntax for a `SELF JOIN` statement: + +```sql +SELECT a.column_name, b.column_name +FROM table_name AS a, table_name AS b +WHERE a.common_field = b.common_field; +``` + +In this query: + +- `table_name`: is the name of the table to join to itself. +- `a` and `b`: are different aliases for the same table. +- `column_name`: specify the columns that should be returned as a result of the SQL `SELF JOIN` statement. +- `WHERE a.common_field = b.common_field`: is the condition for the join. + +## Example of a Self Join + +Let us consider a `EMPLOYEES` table with the following structure: + +| EmployeeID | Name | ManagerID | +|------------|-------|-----------| +| 1 | Sam | NULL | +| 2 | Alex | 1 | +| 3 | John | 1 | +| 4 | Sophia| 2 | +| 5 | Emma | 2 | + +If you want to find out all the employees and who their manager is, you can do so using a `SELF JOIN`: + +```sql +SELECT a.Name AS Employee, b.Name AS Manager +FROM EMPLOYEES a, EMPLOYEES b +WHERE a.ManagerID = b.EmployeeID; +``` + +This query will return the name of each employee along with the name of their respective manager. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/106-join-queries/105-cross-join.md b/src/data/roadmaps/sql/content/106-join-queries/105-cross-join.md new file mode 100644 index 000000000..722523e81 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/105-cross-join.md @@ -0,0 +1,37 @@ +# Cross Join + +The cross join in SQL is used to combine every row of the first table with every row of the second table. It's also known as the Cartesian product of the two tables. The most important aspect of performing a cross join is that it does not require any condition to join. + +The issue with cross join is it returns the Cartesian product of the two tables, which can result in large numbers of rows and heavy resource usage. It's hence critical to use them wisely and only when necessary. + +## Syntax + +Here's the generic syntax for implementing a CROSS JOIN: + +```sql +SELECT column_name(s) +FROM table1 +CROSS JOIN table2; +``` + +You can alternatively use the below syntax to achieve the same result: + +```sql +SELECT column_name(s) +FROM table1, table2; +``` +Both syntax return the Cartesian product of `table1` and `table2`. + +## Example of CROSS JOIN + +Let's consider two tables, `Employees` and `Departments`, where `Employees` has columns `EmpID, EmpName, DeptID` and `Departments` has columns `DeptID, DeptName`. + +A cross join query would look like this: + +```sql +SELECT Employees.EmpName, Departments.DeptName +FROM Employees +CROSS JOIN Departments; +``` + +This statement will return a result set which is the combination of each row from `Employees` with each row from `Departments`. diff --git a/src/data/roadmaps/sql/content/106-join-queries/index.md b/src/data/roadmaps/sql/content/106-join-queries/index.md new file mode 100644 index 000000000..9e9f6f778 --- /dev/null +++ b/src/data/roadmaps/sql/content/106-join-queries/index.md @@ -0,0 +1,62 @@ +# JOIN Queries + +Absolutely, here's a brief summary about SQL JOIN Queries: + +# SQL JOIN Queries + +JOIN clause is used to combine rows from two or more tables, based on a related column between them. + +## INNER JOIN: + +Inner join returns records that have matching values in both tables. For example: + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +INNER JOIN Customers +ON Orders.CustomerID = Customers.CustomerID; +``` + +## LEFT (OUTER) JOIN: + +Returns all records from the left table, and the matched records from the right table. Also returns NULL if there is no match. Example: + +```sql +SELECT Customers.CustomerName, Orders.OrderID +FROM Customers +LEFT JOIN Orders +ON Customers.CustomerID = Orders.CustomerID; +``` + +## RIGHT (OUTER) JOIN: + +Returns all records from the right table, and the matched records from the left table. Also returns null if there is no match. Example: + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +RIGHT JOIN Customers +ON Orders.CustomerID = Customers.CustomerID; +``` +## FULL (OUTER) JOIN: + +Returns all records when there is a match in either left (table1) or right (table2) table records. Also returns null if there is no match. Example: + +```sql +SELECT Customers.CustomerName, Orders.OrderID +FROM Customers +FULL OUTER JOIN Orders +ON Customers.CustomerID = Orders.CustomerID; +``` +## SELF JOIN: + +Self join is a regular join, but the table is joined with itself. Example: + +```sql +SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2, A.City +FROM Customers A, Customers B +WHERE A.CustomerID <> B.CustomerID +AND A.City = B.City; +``` + +**Note**: JOINS can be used with SELECT, UPDATE, and DELETE statements. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/100-types/100-scalar.md b/src/data/roadmaps/sql/content/107-sub-queries/100-types/100-scalar.md new file mode 100644 index 000000000..7d32d2971 --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/100-types/100-scalar.md @@ -0,0 +1,74 @@ +# Scalar + +In SQL, a scalar type is a type that holds a single value as opposed to composite types that hold multiple values. In simpler terms, scalar types represent a single unit of data. + +Some common examples of scalar types in SQL include: + +- Integers (`INT`) +- Floating-point numbers (`FLOAT`) +- Strings (`VARCHAR`, `CHAR`) +- Date and Time (`DATE`, `TIME`) +- Boolean (`BOOL`) + +## Examples + +Here is how you can define different scalar types in SQL: + +## Integers + +An integer can be defined using the INT type. Here is an example of how to declare an integer: + +```sql +CREATE TABLE Employees ( + EmployeeID INT, + FirstName VARCHAR(50), + LastName VARCHAR(50) +); +``` + +## Floating-Point Numbers + +Floating-point numbers can be defined using the FLOAT or REAL type. Here is an example of how to declare a floating-point number: + +```sql +CREATE TABLE Products ( + ProductID INT, + Price FLOAT +); +``` + +## Strings + +Strings can be defined using the CHAR, VARCHAR, or TEXT type. Here is an example of how to declare a string: + +```sql +CREATE TABLE Employees ( + EmployeeID INT, + FirstName VARCHAR(50), + LastName VARCHAR(50) +); +``` + +## Date and Time + +The DATE, TIME or DATETIME type can be used to define dates and times: + +```sql +CREATE TABLE Orders ( + OrderID INT, + OrderDate DATE +); +``` + +## Boolean + +Booleans can be declared using the BOOL or BOOLEAN type. They hold either `TRUE` or `FALSE`. + +```sql +CREATE TABLE Employees ( + EmployeeID INT, + IsActive BOOL +); +``` + +Remember, the way these types are declared might slightly differ based on the SQL dialect you are using. It's crucial to refer to the specific documentation of the SQL flavor you're working with for the precise syntax and behavior. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/100-types/101-column.md b/src/data/roadmaps/sql/content/107-sub-queries/100-types/101-column.md new file mode 100644 index 000000000..7a6c08b33 --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/100-types/101-column.md @@ -0,0 +1,39 @@ +# Column + +In SQL, columns are used to categorize the data in a table. A column serves as a structure that stores a specific type of data (ints, str, bool, etc.) in a table. Each column in a table is designed with a type, which configures the data that it can hold. Using the right column types and size can help to maintain data integrity and optimize performance. + +## **Common SQL Column Types** + +1. **CHAR(n)** - It is a fixed-length character string that holds `n` characters. The size can be 1 to 255. For example, + ```sql + CREATE TABLE Employee(ID CHAR(25)); + ``` + +2. **VARCHAR(n)** - A variable-length character string up to `n` characters where `n` can be from 1 to 255. For example, + ```sql + CREATE TABLE Employee(ID VARCHAR(100)); + ``` + +3. **INT** - This type is used for integers. For example, + ```sql + CREATE TABLE Customers(Age INT); + ``` + +4. **DECIMAL(p,s)** - This is a decimal type used for precision and scale. `p` represents the total number of digits and `s` for numbers after the decimal. For example, + ```sql + CREATE TABLE Products(Price DECIMAL(5,2)); + ``` + +5. **DATE** - This type is used for date format 'YYYY-MM-DD'. For example, + ```sql + CREATE TABLE Orders(OrderedDate DATE); + ``` + +6. **BOOL** - It stores Boolean data types. It can only take `True` or `False` values. For example, + ```sql + CREATE TABLE Users(IsActive BOOL); + ``` + +In SQL, the column type helps in interpreting what kind of data to store in which column, whether it's number, text, date, or logical data. Remember, a table contains multiple columns and each column should have its unique name. + +When creating a table, you should specify the column names, types, and maximum length of the type [if required]. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/100-types/102-row.md b/src/data/roadmaps/sql/content/107-sub-queries/100-types/102-row.md new file mode 100644 index 000000000..672d48c52 --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/100-types/102-row.md @@ -0,0 +1,43 @@ +# Row + +In SQL, a "row" refers to a record in a table. Each row in a table represents a set of related data, and every row in the table has the same structure. + +For instance, in a table named "customers", a row may represent one customer, with columns containing information like ID, name, address, email, etc. + +Here is a conceptual SQL table: + +| ID | NAME | ADDRESS | EMAIL | +|----|------|---------|-------| +| 1 | John | NY | john@example.com | +| 2 | Jane | LA | jane@example.com | +| 3 | Jim | Chicago | jim@example.com | + +Each of these line of data is referred to as a 'row' in the SQL table. + +To select a row, you would use a `SELECT` statement. Here's an example of how you might select a row: + +```sql +SELECT * +FROM customers +WHERE ID = 1; +``` + +This would output: + +| ID | Name | ADDRESS | Email | +|---|------|---------|--------| +| 1 | John | NY | john@example.com | + +The `*` in the statement refers to all columns. If you want to only select specific columns, you can replace `*` with the column name(s): + +```sql +SELECT NAME, EMAIL +FROM customers +WHERE ID = 1; +``` + +In this case, the output would be: + +| Name | Email | +|-----|--------| +| John | john@example.com | diff --git a/src/data/roadmaps/sql/content/107-sub-queries/100-types/103-table.md b/src/data/roadmaps/sql/content/107-sub-queries/100-types/103-table.md new file mode 100644 index 000000000..4897c26bc --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/100-types/103-table.md @@ -0,0 +1,48 @@ +# Table + +In SQL, a table is a collection of related data held in a structured format within a database. It consists of rows (records) and columns (fields). + +A table is defined by its name and the nature of data it will hold, i.e., each field has a name and a specific data type. + +## Table Creation + +You can create a table using the `CREATE TABLE` SQL statement. The syntax is as follows: + +```sql +CREATE TABLE table_name ( + column1 datatype, + column2 datatype, + column3 datatype, + .... +); +``` +Here, `table_name` is the name of the table, `column1`, `column2`... are the names of the columns, and `datatype` specifies the type of data the column can hold (e.g., varchar, integer, date, etc.). + +## Table Manipulation + +Once a table has been created, the `INSERT INTO` statement is used to insert new rows of data into the table. + +```sql +INSERT INTO table_name (column1, column2, column3,...) +VALUES (value1, value2, value3,...); +``` +The `SELECT` statement is used to select data from the table. + +```sql +SELECT column1, column2,... +FROM table_name; +``` +The `UPDATE` statement is used to modify existing records. + +```sql +UPDATE table_name +SET column1 = value1, column2 = value2,... +WHERE condition; +``` +And, finally, the `DELETE` statement is used to delete existing records. + +```sql +DELETE FROM table_name WHERE condition; +``` + +These basic operations allow for full manipulation of tables in SQL, letting users to manage their data effectively. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/100-types/index.md b/src/data/roadmaps/sql/content/107-sub-queries/100-types/index.md new file mode 100644 index 000000000..f3907ab89 --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/100-types/index.md @@ -0,0 +1,62 @@ +# Types of Sub Queries + +Subqueries, sometimes referred to as inner queries or nested queries, are queries that are embedded within the clause of another SQL query. There are different types of SQL subqueries that are frequently used including Scalar, Row, Column, and Table subqueries. + +## Scalar Subqueries + +A scalar subquery is a query that returns exactly one column with a single value. This type of subquery can be used anywhere in your SQL where expressions are allowed. + +Example: + +```sql + SELECT column_name [, column_name ] + FROM table1 [, table2 ] + WHERE column_name operator + (SELECT column_name [, column_name ] + FROM table_name + WHERE condition); +``` + +## Row Subqueries + +Row subqueries are used to return one or more rows to the outer SQL select query. However, the subquery returns multiple columns and rows, so it cannot be directly used where scalar expressions are used. + +Example: + +```sql + SELECT column_name [, column_name ] + FROM table1 [, table2 ] + WHERE (column_name [, column_name ]) + IN (SELECT column_name [, column_name ] + FROM table_name + WHERE condition); +``` + +## Column Subqueries + +Column Subqueries are used to return one or more columns to the outer SQL select query. They are used when the subquery is expected to return more than one column to the main query. + +Example: + +```sql + SELECT column_name [, column_name ] + FROM table1 [, table2 ] + WHERE (SELECT column_name [, column_name ] + FROM table_name + WHERE condition); +``` + +## Table Subqueries + +Table subqueries are used in the FROM clause and return a table that can be used as a table-reference in an SQL statement. They come in handy when you want to perform operations such as joining multiple tables, union data from multiple sources, etc. + +Example: + +```sql + SELECT column_name [, column_name ] + FROM + (SELECT column_name [, column_name ] + FROM table1 [, table2 ]) + WHERE condition; +``` +Remember that not all SQL databases support all types of subqueries. Learning how and when to utilize each form is an essential aspect of constructing effective SQL queries. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/101-nested-subqueries.md b/src/data/roadmaps/sql/content/107-sub-queries/101-nested-subqueries.md new file mode 100644 index 000000000..fa11ba0e5 --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/101-nested-subqueries.md @@ -0,0 +1,42 @@ +# Nested Subqueries + +In SQL, a subquery is a query that is nested inside a main query. If a subquery is nested inside another subquery, it is called a nested subquery. They can be used in SELECT, INSERT, UPDATE, or DELETE statements or inside another subquery. + +Nested subqueries can get complicated quickly, but they are essential for performing complex database tasks. + +## Basic Syntax: + +```sql +SELECT column_name [, column_name ] +FROM table1 [, table2 ] +WHERE column_name OPERATOR + (SELECT column_name [, column_name ] + FROM table1 [, table2 ] + [WHERE]) +``` + +## How They Work: + +In a nested subquery, the inner subquery will run first and its result will be used to run the outer query. + +## Example: + +Here's an example where we want to find the customer names who made orders above the average order amount. + +```sql +SELECT CustomerName,Country +FROM Customers +WHERE CustomerID IN + (SELECT CustomerID + FROM Orders + WHERE Amount>(SELECT AVG(Amount) + FROM Orders)) +``` + +In the above code: + +- The innermost query calculates the average order amount. +- The middle subquery finds the `CustomerID`s from the `Orders` table where the order `Amount` is greater than the average. +- The outer query then gets the `CustomerName` from the `Customers` table where the `CustomerID` is in the list of `CustomerID`s fetched from the middle subquery. + +These are the basic aspects of nested subqueries in SQL. They can go as deep as the task requires, but keep in mind that too many nested subqueries can cause performance issues. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/102-correlated-subqueries.md b/src/data/roadmaps/sql/content/107-sub-queries/102-correlated-subqueries.md new file mode 100644 index 000000000..acf9a51cc --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/102-correlated-subqueries.md @@ -0,0 +1,33 @@ +# Correlated Subqueries + +In SQL, a correlated subquery is a subquery that uses values from the outer query in its WHERE clause. The correlated subquery is evaluated once for each row processed by the outer query. It exists because it depends on the outer query and it cannot execute independently of the outer query because the subquery is correlated with the outer query as it uses its column in its WHERE clause. + +## Syntax: + +```sql +SELECT column_name [, column_name...] +FROM table1 [, table2...] +WHERE column_name OPERATOR + (SELECT column_name [, column_name...] + FROM table_name + WHERE condition [table1.column_name = table2.column_name...]); +``` + +## Code Example + +For instance, if you want to get the employees whose salaries are above their department's average salaries, it can be queried with a correlated subquery as follows: + +```sql +SELECT e1.employee_name, e1.salary +FROM employee e1 +WHERE salary > + (SELECT AVG(salary) + FROM employee e2 + WHERE e1.department = e2.department); +``` + +In the example above, the correlated subquery (the inner query) calculates the average salary for each department. The outer query then compares the salary of each employee to the average salary of their respective department. It returns the employees whose salaries are above their department's average. The correlated subquery is executed once for each row selected by the outer query. + +Also note that `e1` and `e2` are the aliases of the `employee` table so that we can use it in both the inner query and outer query. Here, `e2.department` in the inner query comes from the outer query's `e1.department`. + +Thus, a correlated subquery is a subquery that depends on the outer SQL query for its values. This means that the subquery is run once for every Row in the outer query, often resulting in quite a bit of processing, and thus slower results. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/107-sub-queries/index.md b/src/data/roadmaps/sql/content/107-sub-queries/index.md new file mode 100644 index 000000000..b1f8e768a --- /dev/null +++ b/src/data/roadmaps/sql/content/107-sub-queries/index.md @@ -0,0 +1,60 @@ +# Sub Queries + +In SQL, a subquery is a query embedded within another SQL query. You can alternately call it a nested or an inner query. The containing query is often referred to as the outer query. Subqueries are utilized to retrieve data that will be used in the main query as a condition to further restrict the data to be retrieved. + +Subqueries can be used in various parts of a query, including: + +- **SELECT** statement +- **FROM** clause +- **WHERE** clause +- **GROUP BY** clause +- **HAVING** clause + +## Syntax + +In general, the syntax can be written as: + +```sql +SELECT column_name [, column_name] +FROM table1 [, table2 ] +WHERE column_name OPERATOR + (SELECT column_name [, column_name] + FROM table1 [, table2 ] + [WHERE]) +``` + +## Types of Subqueries + +1. **Scalar Subquery**: It returns single value. + + ```sql + SELECT name + FROM student + WHERE roll_id = (SELECT roll_id FROM student WHERE name='John'); + ``` + +2. **Row subquery**: It returns single row of two or more values. + + ```sql + SELECT * FROM student + WHERE (roll_id, age)=(SELECT MIN(roll_id),MIN(age) FROM student); + ``` + +3. **Column subquery**: It returns single column value which is more than one row and one column. + + ```sql + SELECT name, age FROM student + WHERE name=(SELECT name FROM student); + ``` + +4. **Table subquery**: It returns more than one row and more than one column. + + ```sql + SELECT name, age + FROM student + WHERE (name, age) IN (SELECT name, age FROM student); + ``` + +## General Note + +Subqueries can be either correlated or uncorrelated. A correlated subquery is a subquery that uses values from the outer query. Conversely, an uncorrelated subquery is a subquery that can be run independently of the outer query. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/100-numeric.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/100-numeric.md new file mode 100644 index 000000000..76b2fc971 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/100-numeric.md @@ -0,0 +1,71 @@ +# Numeric + +SQL numeric functions are used to perform operations on numeric data types such as integer, decimal, and float. They're fundamental in manipulating data in SQL commands and are commonly used in `SELECT`, `UPDATE`, `DELETE` and `INSERT` statements. + +## Examples of SQL Numeric Functions: + +1. **ABS() Function:** This function returns the absolute (positive) value of a number. + +```sql +SELECT ABS(-243); +``` +Output: + + 243 + +2. **Avg() Function:** This function returns the average value of a column. + +```sql +SELECT AVG(price) FROM products; +``` + +3. **COUNT() Function:** This function returns the number of rows that matches a specified criterion. + +```sql +SELECT COUNT(productID) FROM products; +``` + +4. **SUM() Function:** This function returns the total sum of a numeric column. + +```sql +SELECT SUM(price) FROM products; +``` + +5. **MIN() & MAX() Functions:** MIN() function returns the smallest value of the selected column, and MAX() function returns the largest value of the selected column. + +```sql +SELECT MIN(price) FROM products; +SELECT MAX(price) FROM products; +``` + +6. **ROUND() Function:** This function is used to round a numeric field to the nearest integer, you can, however, specify the number of decimals to be returned. + +```sql +SELECT ROUND(price, 2) FROM products; +``` + +7. **CEILING() Function:** This function returns the smallest integer which is greater than, or equal to, the specified numeric expression. + +```sql +SELECT CEILING(price) FROM products; +``` + +8. **FLOOR() Function:** This function returns the largest integer which is less than, or equal to, the specified numeric expression. + +```sql +SELECT FLOOR(price) FROM products; +``` + +9. **SQRT() Function:** This function returns the square root of a number. + +```sql +SELECT SQRT(price) FROM products; +``` + +10. **PI() Function:** This function returns the constant Pi. + +```sql +SELECT PI(); +``` + +These are just a few examples, SQL supports many more mathematical functions such as SIN, COS, TAN, COT, POWER, etc. Understanding and using these SQL numeric functions allows you to perform complex operations on the numeric data in your SQL tables. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-round.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-round.md new file mode 100644 index 000000000..27e499284 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-round.md @@ -0,0 +1,45 @@ +# ROUND + +The `ROUND` function in SQL is used to round a numeric field to the nearest specified decimal or integer. + +Most usually, `ROUND` accepts two arguments. The first one is the value that needs to be rounded, and the second is the number of decimal places to which the first argument will be rounded off. When dealing with decimals, SQL will round up when the number after the decimal point is 5 or higher, whereas it will round down if it's less than 5. + +## Syntax + +The basic syntax for `ROUND` can be described as follows: + +```sql +ROUND ( numeric_expression, length [ , function ] ) +``` +- `numeric_expression`: A floating point number to round. +- `length`: The precision to which `numeric_expression` is to be rounded. When `length` is a positive number, rounding affects the right side of the decimal point. If `length` is negative, rounding affects the left side of the decimal point. +- `function`: Optional parameter to determine the operation to perform. If this is omitted or 0, the `numeric_expression` is rounded. If this is 1, the `numeric_expression` is truncated. + +## Example 1: + +Round off a decimal to the nearest whole number. + +```sql +SELECT ROUND(125.215); +``` +This will result in `125`. + +## Example 2: + +Round off a number to a specified decimal place. + +```sql +SELECT ROUND(125.215, 1); +``` +This will result in `125.2` as the second decimal place (5) is less than 5. + +## Example 3: + +Round off the left side of the decimal. + +```sql +SELECT ROUND(125.215, -2); +``` +This will result in `100` as rounding now affects digits before the decimal point. + +Whenever you need to round off numeric data in SQL, the `ROUND` function is a valuable tool to have in your kit. It proficiently handles both positive and negative rounding, and its simple syntax makes it extremely user-friendly. diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/100-concat.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/100-concat.md new file mode 100644 index 000000000..c8194fa0c --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/100-concat.md @@ -0,0 +1,41 @@ +# CONCAT + +`CONCAT` is a SQL function that allows you to concatenate, or join, two or more strings together. This is extremely useful whenever you need to combine text from multiple columns into a single column. + +The syntax for the `CONCAT` function is quite simple: + +```sql +CONCAT(string1, string2, ..., string_n) +``` + +This function accepts as input any number of string arguments, from two to as many as needed, and returns a new string which is the result of all the input strings joined together. The strings are concatenated in the order in which they are passed to the function. + +Here's a simple example: + +```sql +SELECT CONCAT('Hello', ' ', 'World'); +``` + +This will return the string: + +``` +'Hello World' +``` + +You can also use `CONCAT` with columns from a table: + +```sql +SELECT CONCAT(first_name, ' ', last_name) AS full_name +FROM employees; +``` + +The above query will return a new column `full_name` which is the result of `first_name` and `last_name` with a space in between. If `first_name` is 'John' and `last_name` is 'Doe', the returned full name would be 'John Doe'. + +However, keep in mind that `CONCAT` will return `NULL` if any of the input strings is `NULL`. To avoid this, you can use the `CONCAT_WS` function which accepts a separator as the first argument and then a list of strings to concatenate. + +```sql +SELECT CONCAT_WS(' ', first_name, last_name) AS full_name +FROM employees; +``` + +The `CONCAT_WS` function will ignore any `NULL` values, only joining the non-NULL values with the provided separator. Hence, 'John NULL' would become just 'John'. diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/101-length.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/101-length.md new file mode 100644 index 000000000..0bbf66797 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/101-length.md @@ -0,0 +1,53 @@ +# LENGTH + +In SQL, `LENGTH` is a built-in function that allows you to find the number of characters in a string or the length of a string. + +Syntax: + +```sql +LENGTH ( string ) +``` +Here, `string` can be any string literal, column or expression resulting in a string. + +## Examples + +Consider an "employees" table: + +| id | first_name | last_name | +|----|------------|-----------| +| 1 | John | Doe | +| 2 | Jane | Smith | +| 3 | Alice | Murphy | + +To compute the length of the first_name field for all records, use the following SQL statement: +```sql +SELECT first_name, LENGTH(first_name) as length_of_first_name +FROM employees; +``` +Output: + +| first_name | length_of_first_name | +|------------|----------------------| +| John | 4 | +| Jane | 4 | +| Alice | 5 | + +## Usage with DISTINCT +`LENGTH` can also be used in conjunction with `DISTINCT` to find the number of distinct lengths of a specific field. +```sql +SELECT DISTINCT LENGTH(first_name) as distinct_length_of_first_name +FROM employees; +``` + +## Usage with WHERE Clause + +It can work in the WHERE clause to return only those records where the length of a specific field meets a certain condition. +```sql +SELECT * +FROM employees +WHERE LENGTH(first_name) > 4; +``` + +Do note that the `LENGTH` function may return different results in different SQL systems due to character set and collation differences. In some systems, `LENGTH()` returns length in characters while in others it could return length in bytes. + +For example, MySQL has separate `CHAR_LENGTH()` and `LENGTH()` functions. `CHAR_LENGTH()` returns the length of the string in characters, while `LENGTH()` in MySQL returns the length of the string in bytes. This can make a difference if your string includes multibyte characters (like UTF-8). In such scenarios, it's always recommended to be sure how your specific SQL system implements `LENGTH` function. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/102-substring.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/102-substring.md new file mode 100644 index 000000000..70e6e91e6 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/102-substring.md @@ -0,0 +1,61 @@ +# SUBSTRING + +The SQL `SUBSTRING` function is used to extract a part of a string, where you can specify the start position and the length of the text. This function can be very beneficial when you only need a specific part of a string. + +## Syntax + +The standardized SQL syntax for `SUBSTRING` is as follows: + +```sql +SUBSTRING(string, start, length) +``` + +Where: + +- `string` is the source string from which you want to extract. +- `start` is the position to start extraction from. The first position in the string is always 1. +- `length` is the number of characters to extract. + +## Usage + +For instance, if you want to extract the first 5 characters from the string 'Hello World': + +```sql +SELECT SUBSTRING('Hello World', 1, 5) as ExtractedString; +``` + +Result: + +```sql +| ExtractedString | +| --------------- | +| Hello | +``` + +You can also use `SUBSTRING` on table columns, like so: + +```sql +SELECT SUBSTRING(column_name, start, length) FROM table_name; +``` + +## SUBSTRING with FROM and FOR + +In some database systems (like PostgreSQL and SQL Server), the `SUBSTRING` function uses a different syntax: + +```sql +SUBSTRING(string FROM start FOR length) +``` + +This format functions the same way as the previously mentioned syntax. + +For example: + +```sql +SELECT SUBSTRING('Hello World' FROM 1 FOR 5) as ExtractedString; +``` + +This would yield the same result as the previous example - 'Hello'. + +## Note + +SQL is case-insensitive, meaning `SUBSTRING`, `substring`, and `Substring` will all function the same way. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/103-replace.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/103-replace.md new file mode 100644 index 000000000..e489a949e --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/103-replace.md @@ -0,0 +1,45 @@ +# REPLACE + +You can use the `REPLACE()` function in SQL to substitute all occurrences of a specified string. + +**Synopsis** + +`REPLACE(input_string, string_to_replace, replacement_string)` + +**Parameters** + +- `input_string`: This is the original string where you want to replace some characters. +- `string_to_replace`: This is the string that will be searched for in the original string. +- `replacement_string`: This is the string that will replace the `string_to_replace` in the original string. + +The `REPLACE()` function is handy when it comes to manipulating and modifying data in various ways, particularly when used in combination with other SQL data-manipulation functions. + +**Examples** + +Suppose we have the following table, `Employees`: + +| EmpId | EmpName | +|-------|---------------------| +| 1 | John Doe | +| 2 | Jane Doe | +| 3 | Jim Smith Doe | +| 4 | Jennifer Doe Smith | + +Here's how you can use the `REPLACE()` function: + +```sql +SELECT EmpId, EmpName, +REPLACE(EmpName, 'Doe', 'Roe') as ModifiedName +FROM Employees; +``` + +After the execution of the above SQL, we will receive: + +| EmpId | EmpName | ModifiedName | +|-------|--------------------|---------------------| +| 1 | John Doe | John Roe | +| 2 | Jane Doe | Jane Roe | +| 3 | Jim Smith Doe | Jim Smith Roe | +| 4 | Jennifer Doe Smith | Jennifer Roe Smith | + +You can see that all occurrences of 'Doe' are replaced with 'Roe'. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/104-upper.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/104-upper.md new file mode 100644 index 000000000..1ca7b0db3 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/104-upper.md @@ -0,0 +1,35 @@ +# UPPER + +`UPPER()` is a built-in string function in SQL. As the name suggests, it is used to convert all letters in a specified string to uppercase. If the string already consists of all uppercase characters, the function will return the original string. + +Syntax for this function is: + +```sql +UPPER(string) +``` + +Here 'string' can be a string value or a column of a table of string(s) type. + +Let's assume a table 'students' with column 'name' as below: + +| name | +|------------| +| John Doe | +| Jane Smith | +| Kelly Will | + +If we want all the names in uppercase, we'll use `UPPER()` function as: + +```sql +SELECT UPPER(name) as 'Upper Case Name' FROM students; +``` + +And we will get: + +| Upper Case Name | +|----------------| +| JOHN DOE | +| JANE SMITH | +| KELLY WILL | + +So, `UPPER()` function helps us to bring an entire string to uppercase for easier comparison and sorting. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/105-lower.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/105-lower.md new file mode 100644 index 000000000..d608bd836 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/105-lower.md @@ -0,0 +1,38 @@ +# LOWER + +`LOWER` is a built-in function in SQL used to return all uppercase character(s) in a string to lowercase. It can be quite useful when performing case-insensitive comparisons or searches in your queries. + +## Syntax: + +The basic syntax for `LOWER` in SQL is: + +``` +LOWER(string) +``` + +Here, 'string' can be a literal string or a column of a table, and the function will return the string with all alphabetic characters converted to lowercase. + +## Example: + +Let's take a look at a very basic example. Assuming we have the following string "SQL is BAE!" and we want to convert it to lower case. + +```sql +SELECT LOWER('SQL is BAE!') AS LowerCaseString; +``` + +Output: +```sql +lowercasestring +---------------- +sql is bae! +``` + +If you are using a column from a table, let's say we have a table 'students' with a column 'Name' and we want to convert all the entries in that column to lowercase: + +```sql +SELECT LOWER(Name) AS LowerCaseName FROM students; +``` + +Here, the LOWER function will return all the names from the 'Name' column in the 'students' table in their lowercase forms. + +Remember, the `LOWER` function doesn't affect the numbers and special characters in the input string, it only converts uppercase alphabetical characters to lowercase. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/index.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/index.md new file mode 100644 index 000000000..f73d0b7b4 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/101-string/index.md @@ -0,0 +1,91 @@ +# String Functions + +In SQL, you can perform various operations on strings, including extracting a string, combining two or more strings, and converting a case of a string. + +## CONCAT Function + +The CONCAT function combines two or more strings into one string. The following is the syntax: + +```sql +CONCAT(string1, string2, ...., string_n) +``` + +Example: + +```sql +SELECT CONCAT('Hello ', 'World'); +``` + +The output of the above SQL statement will be 'Hello World'. + +## SUBSTRING Function + +The SUBSTRING function extracts a string from a given string. The syntax looks as follows: + +```sql +SUBSTRING(string, start, length) +``` + +Example: + +```sql +SELECT SUBSTRING('SQL Tutorial', 1, 3); +``` + +The output of the above query will be 'SQL'. + +## LENGTH Function + +The LENGTH function returns the length of a string. The syntax is: + +```sql +LENGTH(string) +``` + +Example: + +```sql +SELECT LENGTH('Hello World'); +``` + +The output of the above SQL statement will be 11. + +## UPPER and LOWER Function + +The UPPER function converts all the letters in a string to uppercase, whereas the LOWER function to lowercase. + +Syntax: + +```sql +UPPER(string) + +LOWER(string) +``` + +Examples: + +```sql +SELECT UPPER('Hello World'); + +SELECT LOWER('Hello World'); +``` +The output of the above SQL statements will be 'HELLO WORLD' and 'hello world' respectively. + +## TRIM Function + +The TRIM function removes leading and trailing spaces of a string. You can also remove other specified characters. + +Syntax: + +```sql +TRIM([LEADING|TRAILING|BOTH] [removal_string] FROM original_string) +``` + +Example: + +```sql +SELECT TRIM(' Hello World '); +SELECT TRIM('h' FROM 'hello'); +``` + +The output of the first query will be 'Hello World' and that of the second query will be 'ello'. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-ceiling.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-ceiling.md new file mode 100644 index 000000000..46dc29663 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-ceiling.md @@ -0,0 +1,24 @@ +# CEILING + +`CEILING` is an advanced SQL function that is used to round up values. The function takes a single argument, which is a numeric or decimal number, and returns the smallest integer that is greater than or equal to the supplied number. + +The syntax for using the `CEILING` function is: + +```sql +CEILING (numeric_expression) +``` + +The `numeric_expression` is an expression of the exact numeric or approximate numeric data type categories, or types that can be implicitly converted to one of these categories. + +For example, you have a table called 'Products' with a 'Price' column. Here's how you can use the `CEILING` function to round up all the prices to the nearest whole number: + +```sql +SELECT ProductName, Price, CEILING (Price) AS RoundedUpPrice +FROM Products; +``` + +In this example, if the original price was $10.25, the `RoundedUpPrice` will be $11. This is because the `CEILING` function rounds up the 'Price' value to the nearest whole number. + +It's essential to remember that `CEILING` always rounds up. So even if the Price is $10.01, the RoundedUpPrice according to `CEILING` would still be $11. If you want to round to the nearest whole number, you might want to use the `ROUND` function instead. + +Another important note is that the return type of `CEILING` will be of the same type as the provided numeric expression. For instance, if you supply a numeric expression of type decimal, the return type will also be of type decimal. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/100-case.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/100-case.md new file mode 100644 index 000000000..73724bc06 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/100-case.md @@ -0,0 +1,47 @@ +# CASE + +`CASE` is a conditional statement in SQL that performs different actions based on different conditions. It allows you to perform IF-THEN-ELSE logic within SQL queries. It can be used in any statement or clause that allows a valid expression. + +There are two forms of the `CASE` statement: + +1. **Simple CASE expression** - It compares an expression to a set of simple expressions to return a result. + +```sql +SELECT column1, column2, +(CASE + WHEN condition1 THEN result1 + WHEN condition2 THEN result2 + ... + ELSE result +END) +FROM table_name; +``` + +2. **Searched CASE expression** - It evaluates a set of Boolean expressions to return a result. + +```sql +SELECT column1, column2, +(CASE + WHEN condition1 THEN result1 + WHEN condition2 THEN result2 + ... + ELSE result +END) +FROM table_name; +``` + +In both forms, `CASE` returns a result_1, result_2, ..., if condition_1, condition_2, ... is true. If no conditions are true, it returns the value in the `ELSE` clause. If the `ELSE` clause is omitted and no conditions are true, it returns NULL. + +Here's a concrete example: + +```sql +SELECT OrderID, Quantity, + (CASE + WHEN Quantity > 30 THEN 'Over 30' + WHEN Quantity = 30 THEN 'Equals 30' + ELSE 'Under 30' + END) AS QuantityText +FROM OrderDetails; +``` + +From the "OrderDetails" table, the statement lists 'OrderID', 'Quantity', and a column named 'QuantityText' that displays 'Over 30' if 'Quantity > 30' or 'Equals 30' if 'Quantity = 30' or 'Under 30' if both conditions are false. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/101-nullif.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/101-nullif.md new file mode 100644 index 000000000..5efd161ce --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/101-nullif.md @@ -0,0 +1,40 @@ +# NULLIF + +`NULLIF` is a built-in conditional function in SQL Server. The `NULLIF` function compares two expressions and returns NULL if they are equal or the first expression if they are not. + +## Syntax + +Here's the syntax of the `NULLIF` function: + +```sql +NULLIF(expression1, expression2); +``` +`NULLIF` compares `expression1` to `expression2`. If `expression1` and `expression2` are equal, the function returns NULL. Otherwise, it returns `expression1`. Both expressions must have the same data type. + +## Example + +Consider the following example: + +```sql +SELECT + first_name, + last_name, + NULLIF(email, 'NA') AS email +FROM + users; +``` +In this SQL Server `NULLIF` function example, if the field email is 'NA', then NULL would be returned. Otherwise the actual `email` field value is returned. + +In another example, consider a division operation: + +```sql +SELECT + avg_salary, + NULLIF(avg_salary, 0) AS avg_salary_no_zero +FROM + positions; +``` + +In this SQL Server `NULLIF` function example, if `avg_salary` field is 0, then NULL would be returned. This is useful to avoid division by zero errors. + +In nutshell, the SQL `NULLIF` function can be handy in many scenarios such as to circumvent division by zero errors or to translate known sentinel values into NULL values that can be handled by SQL's NULL handling functions. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/102-coalesce.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/102-coalesce.md new file mode 100644 index 000000000..dc56261a1 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/102-coalesce.md @@ -0,0 +1,28 @@ +# COALESCE + +The `COALESCE` function in SQL is used to manage NULL values in data. It scans from left to right through the arguments and returns the first argument that is not `NULL`. + +Syntax: +```sql +COALESCE(value1,value2,..., valueN) +``` +The `COALESCE` function allows handling the case where you have possible `NULL` values in your data and you want to replace it with some other value. + +For instance, here is an example of how you might use `COALESCE`: + +```sql +SELECT product_name, COALESCE(price, 0) AS Price +FROM products; +``` +In this example, if the "price" column for a product entry is `NULL`, it will instead return "0". + +Another common use case is using `COALESCE` to find the first non-NULL value in a list: + +```sql +SELECT COALESCE(NULL, NULL, 'third value', 'fourth value'); +``` +In this case, it would return "third value", as that's the first non-NULL value in the list. + +Remember, `COALESCE` does not update the original data. It only returns the first non-NULL value in the runtime. To update any NULL values permanently, you would need to use an `UPDATE` statement. + +The `COALESCE` function in SQL improves the reliability of your queries when null values are involved. Whether it's replacing nulls with default values or finding the earliest valid date, it's a very useful function to grasp. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/index.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/index.md new file mode 100644 index 000000000..78599c28f --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/102-conditional/index.md @@ -0,0 +1,67 @@ +# Conditional + +In SQL, Conditional expressions can be used in the SELECT statement, WHERE clause, and ORDER BY clause to evaluate multiple conditions. These are SQL's version of the common if…then…else statement in other programming languages. + +There are two kinds of conditional expressions in SQL: + +1. **CASE** expression + + The `CASE` expression is a flow-control statement that allows you to add if-else logic to a query. It comes in two forms: simple and searched. + + Here is an example of a simple `CASE` expression: + + ```sql + SELECT OrderID, Quantity, + CASE + WHEN Quantity > 30 THEN 'Over 30' + ELSE 'Under 30' + END AS QuantityText + FROM OrderDetails; + ``` + A searched `CASE` statement: + + ```sql + SELECT FirstName, City, + CASE + WHEN City = 'Berlin' THEN 'Germany' + WHEN City = 'Madrid' THEN 'Spain' + ELSE 'Unknown' + END AS Country + FROM Customers; + ``` + +2. **COALESCE** expression + + The `COALESCE` function returns the first non-null value in a list. It takes a comma-separated list of values and returns the first value that is not null. + + An example of a `COALESCE` statement: + + ```sql + SELECT ProductName, + COALESCE(UnitsOnOrder, 0) As UnitsOnOrder, + COALESCE(UnitsInStock, 0) As UnitsInStock, + FROM Products; + ``` + +3. **NULLIF** expression + + `NULLIF` returns null if the two given expressions are equal. + + Example of using `NULLIF`: + + ```sql + SELECT NULLIF(5,5) AS Same, + NULLIF(5,7) AS Different; + ``` + +4. **IIF** expression + + `IIF` function returns value_true if the condition is TRUE, or value_false if the condition is FALSE. + + Example of using `IIF`: + + ```sql + SELECT IIF (1>0, 'One is greater than zero', 'One is not greater than zero'); + ``` + +These are essential constructs that can greatly increase the flexibility and functionality of your SQL code, particularly when dealing with elaborate conditions and specific data selections. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/100-date.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/100-date.md new file mode 100644 index 000000000..278272dc6 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/100-date.md @@ -0,0 +1,76 @@ +# DATE + +In SQL, DATE is a data type that stores the date. It does not store time information. The format of the date is, 'YYYY-MM-DD'. For instance, '2022-01-01'. SQL provides several functions to handle and manipulate dates. + +Below are some common examples of how to use the DATE data type in SQL: + +## Create a table with DATE data type + +```sql +CREATE TABLE Orders ( + OrderId int, + ProductName varchar(255), + OrderDate date +); +``` + +In this example, the OrderDate column uses the DATE data type to store the date of the order. + +## Insert a date value into a table + +```sql +INSERT INTO Orders (OrderId, ProductName, OrderDate) +VALUES (1, 'Product 1', '2022-01-01'); +``` + +This command inserts a new row into the Orders table with a date. + +## Retrieve data with a specific date + +```sql +SELECT * FROM Orders +WHERE OrderDate = '2022-01-01'; +``` + +This command retrieves all orders made on January 1, 2022. + +## Update a date value in a table + +```sql +UPDATE Orders +SET OrderDate = '2022-01-02' +WHERE OrderId = 1; +``` + +This command updates the date from January 1, 2022 to January 2, 2022, for the order with the order ID 1. + +## SQL Date Functions + +SQL also provides several built-in functions to work with the DATE data type: + +## CURRENT_DATE + +Returns the current date. + +```sql +SELECT CURRENT_DATE; +``` + +## DATEADD + +Add or subtract a specified time interval from a date. + +```sql +SELECT DATEADD(day, 5, OrderDate) AS "Due Date" +FROM Orders; +``` +In this example, we are adding 5 days to each OrderDate in the table Orders. + +## DATEDIFF + +Get the difference between two dates. + +```sql +SELECT DATEDIFF(day, '2022-01-01', '2022-01-06') AS "Difference"; +``` +It will return 5, that is the difference in days between the two dates. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/101-time.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/101-time.md new file mode 100644 index 000000000..0a0908422 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/101-time.md @@ -0,0 +1,65 @@ +# TIME + +In SQL, TIME data type is used to store time values in the database. It allows you to store hours, minutes, and seconds. The format of a TIME is 'HH:MI:SS'. + +## Syntax + +Here is the basic syntax to create a field with TIME data type in SQL: +```sql +CREATE TABLE table_name ( + column_name TIME +); +``` + +You can store data using the following syntax: +```sql +INSERT INTO table_name (column_name) values ('17:34:20'); +``` + +## Range + +The time range in SQL is '00:00:00' to '23:59:59'. + +## Fetching Data + +To fetch the data you can use the SELECT statement. For example: + +```sql +SELECT column_name FROM table_name; +``` +It will return the time values from the table. + +## Functions + +SQL provides several functions to work with the TIME data type. Some of them include: + +## CURTIME() + +Return the current time. +```sql +SELECT CURTIME(); +``` + +## ADDTIME() + +Add time values. +```sql +SELECT ADDTIME('2007-12-31 23:59:59','1 1:1:1'); +``` + +## TIMEDIFF() + +Subtract time values. +```sql +SELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:01:01'); +``` + +## Conversion + +Conversion of TIME data type is also possible in SQL. It can be converted into other data types, like INT, and vice versa. Here is a conversion example of TIME to INT: + +```sql +SELECT TIME_TO_SEC('22:23:00'); +``` + +This was a brief summary about "TIME" in SQL. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/102-datepart.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/102-datepart.md new file mode 100644 index 000000000..ae625ab75 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/102-datepart.md @@ -0,0 +1,49 @@ +# DATEPART + +`DATEPART` is a useful function in SQL that allows you to extract a specific part of a date or time field. You can use it to get the year, quarter, month, day of the year, day, week, weekday, hour, minute, second, or millisecond from any date or time expression. + +Here's the basic syntax of `DATEPART`: + +```sql +DATEPART(datepart, date) +``` + +Here `datepart` is the part of the date that you want to extract, and `date` is the date value from which the part should be extracted. + +Here are some examples: + +1. Extracting the year from a date: + +```sql +SELECT DATEPART(year, '2021-07-14') AS 'Year'; +``` + +In this example, it would return `2021`. + +2. Extracting the month: + +```sql +SELECT DATEPART(month, '2021-07-14') AS 'Month'; +``` + +The result of this command would be `7`. + +3. Extracting the day: + +```sql +SELECT DATEPART(day, '2021-07-14') AS 'Day'; +``` + +This would return `14`. + +4. Extracting the hour, minute, or second from a datetime: + +```sql +SELECT DATEPART(hour, '2021-07-14T13:30:15') AS 'Hour', + DATEPART(minute, '2021-07-14T13:30:15') AS 'Minute', + DATEPART(second, '2021-07-14T13:30:15') AS 'Second'; +``` + +This would return `13`, `30`, and `15` respectively. + +Remember, the `DATEPART` function returns an integer value. It is essential when you want to compare or group by a specific part of a date or time field in SQL. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/103-dateadd.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/103-dateadd.md new file mode 100644 index 000000000..a2b7e7072 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/103-dateadd.md @@ -0,0 +1,45 @@ +# DATEADD + +`DATEADD` is a built-in function in SQL that allows you to add or subtract units of time from a specified date. The function takes three parameters: + +- An interval type (such as day, month, year, hour, minute, second) +- A number (which can be either positive, for future dates, or negative, for past dates) +- A date from which calculation will be based. + +The usage of this function can be especially useful when you need to perform operations on dates, such as finding a date "n" days before or after a specified date, or getting the first or last day of a month. + +## Syntax + +The generic syntax for `DATEADD` is: + +```sql +DATEADD(interval, number, date) +``` +Here's what each param means: + +- `interval`: The part of date to which an integer value will be added. This could be a year, quarter, month, day, hour, minute, second, millisecond, microsecond, or nanosecond. + +- `number`: The value to add. The value can either be negative to get dates in the past or positive to get dates in the future. + +- `date`: The date or datetime expression to which the interval and number are added. + +For example, if we want to add three days to the date '2022-01-01', we would write: + +```sql +SELECT DATEADD(day, 3, '2022-01-01') as NewDate +``` + +The result would be: `2022-01-04`. + +You can substitute 'day' with any of the accepted interval types to add different units of time. + +## Sample Query + +If you have a table called `Orders` with a `DateTime` field `OrderDate` and you want to find all orders placed in the next seven days, you can use the `DATEADD` function as follows: + +```sql +SELECT * FROM Orders +WHERE OrderDate <= DATEADD(day, 7, GETDATE()) +``` + +This will return all orders from now until a week from now. diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/104-timestamp.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/104-timestamp.md new file mode 100644 index 000000000..1fd8dc3ad --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/104-timestamp.md @@ -0,0 +1,45 @@ +# TIMESTAMP + +SQL `TIMESTAMP` is a data type that allows you to store both date and time. It is typically used to track updates and changes made to a record, providing a chronological time of happenings. + +Depending on the SQL platform, the format and storage size can slightly vary. For instance, MySQL uses the 'YYYY-MM-DD HH:MI:SS' format and in PostgreSQL, it's stored as a 'YYYY-MM-DD HH:MI:SS' format but it additionally can store microseconds. + +Here is how you can define a column with a `TIMESTAMP` type in an SQL table: + +```sql +CREATE TABLE table_name ( + column1 TIMESTAMP, + column2 VARCHAR(100), + ... +); +``` + +A common use-case of `TIMESTAMP` is to have an automatically updated timestamp each time the row is updated. This can be achieved by setting the `DEFAULT` constraint to `CURRENT_TIMESTAMP`: + +```sql +CREATE TABLE table_name ( + column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + column2 VARCHAR(100), + ... +); +``` + +In MySQL, `ON UPDATE CURRENT_TIMESTAMP` can be used to automatically update the `TIMESTAMP` field to the current date and time whenever there is any change in other fields of the row. + +```sql +CREATE TABLE table_name ( + column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + column2 VARCHAR(100), + ... +); +``` + +You can also insert or update records with a specific timestamp: + +```sql +INSERT INTO table_name (column1, column2) VALUES ('2019-06-10 10:20:30', 'example data'); + +UPDATE table_name SET column1 = '2020-07-20 15:30:45' WHERE column2 = 'example data'; +``` + +Remember that the format of the date and time you enter must correspond to the format used by the SQL platform you are using. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/index.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/index.md new file mode 100644 index 000000000..9a499ee2a --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-date-time/index.md @@ -0,0 +1,47 @@ +# Date and Time + +In SQL, the `DateTime` data type is used to work with dates and times. SQL Server comes with numerous functions for processing dates and times. Some of these include `GETDATE()`, `DATEDIFF()`, `DATEADD()`, `CONVERT()`, and so forth. + +## GETDATE() + +`GETDATE()` returns the current date and time as a DateTime datatype. It does not require any arguments. + +```sql +SELECT GETDATE() AS CurrentDateTime; +``` + +## DATEDIFF() + +`DATEDIFF()` returns the difference between two date values based on the unit of time you want to use. The syntax is `DATEDIFF(datepart, startdate, enddate)`. + +```sql +SELECT DATEDIFF(day, '2022-01-01', '2022-01-15') AS DiffInDays; +``` + +## DATEADD() + +`DATEADD()` adds or subtracts a specified time interval from a date. Its syntax is `DATEADD(datepart, number, date)`. + +```sql +SELECT DATEADD(year, 1, '2022-01-01') AS NewDate; +``` + +## CONVERT() + +`CONVERT()` is used to convert from one data type to another, and it is commonly used to format DateTime values. Its syntax is `CONVERT(data_type(length), expression, style)`. + +```sql +SELECT CONVERT(VARCHAR(19), GETDATE()) AS FormattedDateTime; +``` +Remember to replace `date` with your date in above queries. + +## DateTime Format + +By using appropriate format codes, SQL allows us to present dates and times in various formats. + +```sql +SELECT FORMAT(GETDATE(), 'MM/dd/yyyy') AS DateFormatted; +``` +Also, by using specific column names instead of `GETDATE()`, the same patterns can be applied to DateTime values in your data. + +Note: All dates are stored as numeric values under the hood, with the integer portion representing the date and the decimal portion representing the time. Also, different database systems may use slightly different functions for handling dates and times, so be sure to check the documentation for your specific DBMS. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-floor.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-floor.md new file mode 100644 index 000000000..5159c0472 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/103-floor.md @@ -0,0 +1,30 @@ +# FLOOR + +The SQL `FLOOR` function is used to round down any specific decimal or numeric value to its nearest whole integer. The returned number will be less than or equal to the number given as an argument. + +One important aspect to note is that the `FLOOR` function's argument must be a number and it always returns an integer. + +## Syntax + +The syntax of using the `FLOOR` function in SQL is as follows: +```sql +FLOOR (number); +``` + +## Example Usage + +Here's a simple example of its usage: + +```sql +SELECT FLOOR(25.75); +``` +The above query will return `25` as the result, as that's the nearest integer less than `25.75`. + +Suppose we have a table called `Orders` with a column `SalePrice` that includes decimal values. If we wanted to round down the `SalePrice` values to the nearest whole numbers, we could use a query like this: + +```sql +SELECT FLOOR(SalePrice) AS RoundedSalePrice +FROM Orders; +``` + +This would output a new column `RoundedSalePrice` where all the sale prices have been rounded down to the nearest integers. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/104-abs.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/104-abs.md new file mode 100644 index 000000000..ec9c8fef7 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/104-abs.md @@ -0,0 +1,38 @@ +# ABS + +The `ABS` function in SQL is used to return the absolute value of a number, i.e., the numeric value without its sign. The function takes a single argument which must be a number (integer, float, etc.) and returns the absolute, non-negative equivalent. + +The general syntax for the ABS function is as follows: + +```sql +ABS(expression) +``` + +In the syntax above, the `expression` is required and can either be a literal number, a column name, the result of another function, or any valid SQL expression that resolves to a numeric value. + +## Examples + +Consider a database table `Orders`: + +| OrderID | Product | Quantity | +|---------|---------|----------| +| 1 | Apple | -5 | +| 2 | Banana | 10 | +| 3 | Cherry | -15 | + +If you want to get the absolute value of the 'Quantity' column, you could use the `ABS`function like this: + +```sql +SELECT OrderID, Product, ABS(Quantity) as 'Absolute Quantity' +FROM Orders; +``` + +The output will be: + +| OrderID | Product | Absolute Quantity | +|---------|---------|-------------------| +| 1 | Apple | 5 | +| 2 | Banana | 10 | +| 3 | Cherry | 15 | + +As you can see, the negative values in the 'Quantity' column have been converted to positive values by the `ABS` function. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/105-mod.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/105-mod.md new file mode 100644 index 000000000..aea1da18b --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/105-mod.md @@ -0,0 +1,33 @@ +# MOD + +The SQL `MOD()` function is a mathematical function that returns the remainder of the values from the division of two numbers. It calculates the modulo operation. This function is very useful when you want to find the remainder value after one number is divided by another. + +## Syntax + +The syntax of the MOD function in SQL is: +```sql +MOD(expression1, expression2) +``` + +- `Expression1` and `Expression2` are the values that you want to apply the function to. + +## Basic Usage + +For instance, if you want to find the remainder of the division of 15 by 4 you would write: +```sql +SELECT MOD(15, 4) as result; +``` +The result would be `3` because 3 is the remainder after dividing 15 by 4. + +## Usage with Table Columns + +The `MOD()` function can also be applied to table columns. Let's imagine that you have a table named "Orders" with an "OrderNumber" column and you want to find the remainder of every order number when divided by 7, you would do: + +```sql +SELECT OrderNumber, MOD(OrderNumber, 7) as result +FROM Orders; +``` + +This will return a list of all order numbers, along with the remainder when each order number is divided by 7. + +Keep in mind that the SQL `MOD()` function may not work in the same way, or might not support all features, in every SQL database. Always refer to the documentation specific to the SQL database you are using. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/108-advanced-sql-functions/index.md b/src/data/roadmaps/sql/content/108-advanced-sql-functions/index.md new file mode 100644 index 000000000..8ade965e0 --- /dev/null +++ b/src/data/roadmaps/sql/content/108-advanced-sql-functions/index.md @@ -0,0 +1,69 @@ +# Advanced SQL Functions + +Advanced SQL functions provide complex data manipulation and query capabilities enabling the user to perform tasks that go beyond the capabilities of basic SQL commands. + +## Window Function + +Windowing Functions provide the ability to perform calculations across sets of rows related to the current query row. + +```sql +SELECT productName, productLine, buyPrice, + AVG(buyPrice) OVER(PARTITION BY productLine) as avg_price +FROM products +ORDER BY productLine, buyPrice; +``` + +## Aggregate Function + +Aggregate functions return a single result row based on groups of rows, rather than on single rows. + +```sql +SELECT COUNT(*) FROM products; +``` + +## Analytic Functions + +Analytic functions compute an aggregate value based on a group of rows. They differ from aggregate functions in that they return multiple rows for each group. + +```sql +SELECT department_id, last_name, hire_date, + COUNT(*) OVER (PARTITION BY department_id) as dept_count, + RANK() OVER (PARTITION BY department_id ORDER BY hire_date) as ranking +FROM employees; +``` + +## Scalar Function + +A scalar function returns a single value each time it is invoked. It is based on the input value. + +```sql +SELECT UPPER(productName) FROM products; +``` + +## Stored Procedures + +Stored Procedures are a prepared SQL code that you can save so the code can be reused over and over again. + +```sql +CREATE PROCEDURE SelectAllProducts @Product varchar(50) +AS +SELECT * FROM products WHERE Product = @Product +GO; +``` + +## String Functions + +Functions that manipulate the string data types. For example, `LEFT()`, `LENGTH()`, `LOWER()`, etc. + +```sql +SELECT LEFT('This is a test', 4); +``` + +## Date Functions + +Functions that manipulate the date data types. For example, `GETDATE()`, `DATEADD()`, `DATEDIFF()`, etc. + +```sql +SELECT GETDATE() AS CurrentDateTime; +``` +Remember, not all types or functions are supported by every SQL distribution but most of them have some sort of equivalent. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/109-views/100-creating.md b/src/data/roadmaps/sql/content/109-views/100-creating.md new file mode 100644 index 000000000..7af9de131 --- /dev/null +++ b/src/data/roadmaps/sql/content/109-views/100-creating.md @@ -0,0 +1,52 @@ +# Creating Views + +In SQL, creating views can be achieved through the `CREATE VIEW` statement. A view is a virtual table based on the result-set of an SQL statement. It contains rows and columns from one or more tables. The syntax for the `CREATE VIEW` statement is: + +```sql +CREATE VIEW view_name AS +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` + +Here: +- `CREATE VIEW view_name` : It creates a new view that you define with `view_name`. +- `AS SELECT column1, column2 ...` : These are the columns you want in your view. You can choose one or more columns from one or more tables. +- `FROM table_name` : `table_name` is the name of the table from which you want to create the view. +- `WHERE` : It is an optional clause that you can use to specify conditions for displaying records. + +**Example:** + +Let's say you have a table named `Employees` having following data: + +| ID | NAME | SALARY | DEPARTMENT_ID | +|----|-------|--------|---------------| +| 1 | John | 3000 | 2 | +| 2 | Sue | 3500 | 3 | +| 3 | Phil | 4500 | 2 | +| 4 | Anna | 5000 | 1 | + +You can create a view that shows only the employees from department 2: + +```sql +CREATE VIEW Department2 AS +SELECT Name, Salary +FROM Employees +WHERE Department_ID = 2; +``` + +After running this statement, `Department2` will be a saved view in your database, and you can query it like you would with a standard table: + +```sql +SELECT * +FROM Department2; +``` + +This would bring up + +| NAME | SALARY | +|------|--------| +| John | 3000 | +| Phil | 4500 | + +In total, the `CREATE VIEW` statement is a useful command when you want to save a particular query and its result set for future use. This can simplify complex queries by breaking them up into manageable parts. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/109-views/101-modifying.md b/src/data/roadmaps/sql/content/109-views/101-modifying.md new file mode 100644 index 000000000..d8f0aaf8d --- /dev/null +++ b/src/data/roadmaps/sql/content/109-views/101-modifying.md @@ -0,0 +1,82 @@ +# Modifying Views + +In SQL, you can modify a VIEW in two ways: + +- Using CREATE OR REPLACE VIEW: This command helps you modify a VIEW but keeps the VIEW name intact. This is beneficial when you want to change the definition of the VIEW but do not want to change the VIEW name. + +- Using the DROP VIEW and then CREATE VIEW: In this method, you first remove the VIEW using the DROP VIEW command and then recreate the view using the new definition with the CREATE VIEW command. + +## Modifying VIEW Using CREATE OR REPLACE VIEW + +Syntax: + +```sql +CREATE OR REPLACE VIEW view_name AS +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` + +Example: + +```sql +CREATE OR REPLACE VIEW customer_view AS +SELECT customer_name, country +FROM customers +WHERE country='USA'; +``` +In this example, 'customer_view' will show the names and countries of customers only from the USA. + +## Modifying VIEW Using DROP VIEW and CREATE VIEW + +Syntax: +Drop the VIEW: +```sql +DROP VIEW view_name; +``` +Create a new VIEW: +```sql +CREATE VIEW view_name AS +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` + +Example: +Drop the VIEW +```sql +DROP VIEW customer_view; +``` +Create a new VIEW: +```sql +CREATE VIEW customer_view AS +SELECT customer_name, country +FROM customers +WHERE country='UK'; +``` +In this example, we first removed 'customer_view'. Then, we created it again with the new definition where it now shows the names and countries of the customers only from the UK. + +**CAUTION**: If other views, stored procedures, or programs depend on this view, they will be affected after you drop the view. For this reason, using CREATE OR REPLACE VIEW is generally safer. + +## Modifying Data through VIEW + +In some cases, you can modify the data of the underlying tables via a VIEW. + +Syntax: + +```sql +UPDATE view_name +SET column1 = value1, column2 = value2, ... +WHERE condition; +``` + +Example: + +```sql +UPDATE customer_view +SET country = 'USA' +WHERE customer_name = 'John Doe'; +``` +This command will update the country of 'John Doe' to 'USA' in both the VIEW and the underlying table. + +However, not every VIEW is updatable. You can only modify the data if the VIEW you're modifying is a simple VIEW that returns results from a single table without any aggregation or complex clauses. If you attempt to modify a complex view (i.e., it includes JOIN, GROUP BY, HAVING, DISTINCT), you will get an error. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/109-views/102-dropping.md b/src/data/roadmaps/sql/content/109-views/102-dropping.md new file mode 100644 index 000000000..ca8454acf --- /dev/null +++ b/src/data/roadmaps/sql/content/109-views/102-dropping.md @@ -0,0 +1,31 @@ +# Dropping Views + +"Dropping" in SQL is the process of deleting an existing database object. In the context of views, "dropping" refers to deleting an existing view from the database. Once a view is dropped, it cannot be used any longer until it is recreated with the same or new definition. If you're going to drop a view, ensure it's not being used anywhere in your application or it will lead to errors. + +## Dropping Views + +You can drop a view in SQL using the `DROP VIEW` statement. The `DROP VIEW` statement removes one or more views from the database. You specify the name of the view that you want to remove after the `DROP VIEW` clause. + +Here is the basic syntax to drop an existing view: + +```sql +DROP VIEW view_name; +``` + +To drop multiple views in a single command, you use a list of comma-separated views. + +```sql +DROP VIEW view_name1, view_name2, ..., view_name_n; +``` + +**Note**: Be careful when dropping views. Once a view is dropped, all the permissions granted on it will also be dropped. + +Before dropping a view, you can check if the view exists by using the `IF EXISTS` parameter. If you drop a view that does not exist, you will get an error. To prevent this, you can use the `IF EXISTS` parameter. + +Here is how you do it: + +```sql +DROP VIEW IF EXISTS view_name; +``` + +In this case, if the view exists, it will be dropped. If the view does not exist, nothing happens and you don't get an error. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/109-views/index.md b/src/data/roadmaps/sql/content/109-views/index.md new file mode 100644 index 000000000..ae84f847b --- /dev/null +++ b/src/data/roadmaps/sql/content/109-views/index.md @@ -0,0 +1,54 @@ +# Views + +SQL views are virtual tables that do not store data directly. They are essentially a saved SQL query and can pull data from multiple tables or just present the data from one table in a different way. + +## Creating Views + +You can create a view using the `CREATE VIEW` statement. In the following example, a new view named `CustomerView` is created which contains customer's ID, name, and address from the `Customers` table: + +```sql +CREATE VIEW CustomerView AS +SELECT CustomerID, Name, Address +FROM Customers; +``` + +## Querying Views + +After a view has been created, it can be used in the `FROM` clause of a `SELECT` statement, as if it's an actual table. For instance, to select all from `CustomerView`: + +```sql +SELECT * +FROM CustomerView; +``` + +## Updating Views + +The `CREATE OR REPLACE VIEW` statement is used to update a view. Consider the `CustomerView` we created earlier. If we want to include the customer's phone, we can update it as follows: + +```sql +CREATE OR REPLACE VIEW CustomerView AS +SELECT CustomerID, Name, Address, Phone +FROM Customers; +``` + +## Dropping Views + +To delete a view, use the `DROP VIEW` statement: + +```sql +DROP VIEW CustomerView; +``` + +Keep in mind that not all database systems support the `CREATE OR REPLACE VIEW` statement. Also, the updatability of a view depends on whether it includes functions, expressions, or multiple tables. Some databases might not let you update a view at all. + +## Restrictions + +There are a few restrictions to bear in mind when working with views. SQL views can't: + +- Contain a `ORDER BY` clause in the view definition +- Be indexed +- Have triggers or default values + +Each database may have its own specific limitations and capabilities with using views, so always refer to the official documentation for more information. + +Note: The above examples use a hypothetical `Customers` table. Replace this with your actual table name when trying these in your environment. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/110-indexes/100-managing-indexes.md b/src/data/roadmaps/sql/content/110-indexes/100-managing-indexes.md new file mode 100644 index 000000000..2e82a0058 --- /dev/null +++ b/src/data/roadmaps/sql/content/110-indexes/100-managing-indexes.md @@ -0,0 +1,48 @@ +# Managing Indexes + +Indexes can drastically speed up data retrieval in SQL databases by allowing the database to immediately locate the data needed without having to scan the entire database. However, these additional data structures also consume storage, and maintaining them can slow down any create, update, or delete operations, hence the need to manage them appropriately. + +## Creating Indexes + +To create an index, you use the `CREATE INDEX` command followed by the index name, the table name, and the columns you want to use in the index. + +```sql +CREATE INDEX index_name +ON table_name(column_name); +``` + +## Removing Indexes + +If an index is no longer required or if it's causing performance issues due to too much storage consumption, it can be dropped using the `DROP INDEX` command. + +```sql +DROP INDEX index_name; +``` + +## Listing Indexes + +You can get a list of all the indexes on a table using the `SHOW INDEXES` command. + +```sql +SHOW INDEXES IN table_name; +``` + +Remember that most SQL databases automatically create indexes for primary keys, and they do not need to be managed manually. + +## Modifying Indexes + +Modifying an existing index often means dropping the old index and creating a new one. PostgreSQL, MySQL, and MS SQL Server provide a way to reindex without dropping and recreating them manually. + +For example, in PostgreSQL: + +```sql +REINDEX INDEX index_name; +``` + +## Indexes and Performance + +While indexes can improve read speed, they also slow down write operations because each write must also update the index. That's why it's essential to find a balance between the number of indexes and database performance. Too many indexes can negatively impact performance. + +Therefore, you should only create indexes when they are likely to be needed and when they will have a significant impact on improving query performance. You can use the SQL Server Profiler, MySQL's slow query log, or other database-specific tools to identify the queries that are running slow, and then create indexes to optimize those queries. Regularly monitor your database performance to make sure that the indexes are still needed and that they are providing the expected improvements. + +Add indexes strategically and purposefully, and do regular cleanups of any unnecessary indexes. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/110-indexes/101-query-optimization.md b/src/data/roadmaps/sql/content/110-indexes/101-query-optimization.md new file mode 100644 index 000000000..10a4e422d --- /dev/null +++ b/src/data/roadmaps/sql/content/110-indexes/101-query-optimization.md @@ -0,0 +1,66 @@ +# Query Optimization + +Query optimization is a function of SQL that involves tuning and optimizing a SQL statement so that the system executes it in the fastest and most efficient way possible. It includes optimizing the costs of computation, communication, and disk I/O. + +The primary approaches of query optimization involve the following: + +## Rewriting Queries + +This means changing the original SQL query to an equivalent one which requires fewer system resources. It's usually done automatically by the database system. + +For instance, let's say we have a query as follows: + +```sql +SELECT * +FROM Customers +WHERE state = 'New York' AND city = 'New York'; +``` + +The above query can be rewritten using a subquery for better optimization: + +```sql +SELECT * +FROM Customers +WHERE state = 'New York' +AND city IN (SELECT city + FROM Customers + WHERE city = 'New York'); +``` + +## Choosing the right index + +Indexes are used to find rows with specific column values quickly. Without an index, SQL has to begin with the first row and then read through the entire table to find the appropriate rows. The larger the table, the more costly the operation. Choosing a right and efficient index greatly influence on query performance. + +For example, + +```sql +CREATE INDEX index_name +ON table_name (column1, column2, ...); +``` + +## Fine-tuning Database Design + +Improper database schema designs could result in poor query performances. While not strictly a part of query optimization, tuning the database design can speed up the query execution time drastically. + +Changes such as the separation of specific data to different tables (Normalization), combining redundant data (Denormalization), or changing the way how tables are linked (Optimized Join Operations), can be implemented to optimize the schema. + +## Use of SQL Clauses wisely + +The usage of certain SQL clauses can help in query optimization like LIMIT, BETWEEN etc. + +Example, + +```sql +SELECT column1, column2 +FROM table_name +WHERE condition +LIMIT 10; +``` + +## System Configuration + +Many database systems allow you to configure system parameters that control its behavior during query execution. For instance, in MySQL, you can set parameters like `sort_buffer_size` or `join_buffer_size` to tweak how MySQL would use memory during sorting and joining operations. + +In PostgreSQL, you can set `work_mem` to control how much memory is utilized during operations such as sorting and hashing. + +Always remember the goal of query optimization is to lessen the system resources usage in terms of memory, CPU time, and thus improve the query performance. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/110-indexes/index.md b/src/data/roadmaps/sql/content/110-indexes/index.md new file mode 100644 index 000000000..4c51ba409 --- /dev/null +++ b/src/data/roadmaps/sql/content/110-indexes/index.md @@ -0,0 +1,72 @@ +# Indexes + +An index in SQL is a database object which is used to improve the speed of data retrieval operations on a database table. Similarly to how an index in a book helps you find information quickly without reading the entire book, an index in a database helps the database software find data quickly without scanning the entire table. + +## Clustered Index + +A clustered index determines the physical order of data inside a table. It sorts and stores the data rows in the table based on their key values. There can be only one clustered index per table. + +Creating a clustered index: + +```sql +CREATE CLUSTERED INDEX index_name +ON table_name (column_name); +``` + +## Non-Clustered Index + +A non-clustered index doesn’t sort the physical data inside the table. Instead, it creates a separate object within a table which points back to the original table rows after creating. You can create numerous non-clustered indexes per table. + +Creating a non-clustered index: + +```sql +CREATE NONCLUSTERED INDEX index_name +ON table_name (column_name); +``` + +## Indexes on Multiple Columns + +An index can be built on more than one column of a table, which results in index entries having values of multiple columns. This is known as a composite index. + +Creating a composite index: + +```sql +CREATE INDEX index_name +ON table_name (column1, column2); +``` + +## Unique Indexes + +A unique index doesn't allow any field to have duplicate values if the field is unique indexed. If a primary key is defined, a unique index can be applied automatically. + +Creating a unique index: + +```sql +CREATE UNIQUE INDEX index_name +ON table_name (column_name); +``` + +## Explicit vs Implicit Indexes + +Indexes explicitly created by users are known as explicit indexes, while indexes automatically created by SQL Server when a primary key or unique constraint is defined are known as implicit indexes. + +Creating an explicit index: + +```sql +CREATE INDEX index_name +ON table_name (column_name); +``` + +## Full-Text Indexes + +If you're dealing with text searching within a large string of text, full-text indexes are especially helpful. These indexes do not work using a standard comparison search but instead use word-breakers, filters, and noise-words (stop words). + +Creating a full-text index: + +```sql +CREATE FULLTEXT INDEX ON table_name +(column_name) +KEY INDEX index_name; +``` + +Please note that the creation and maintenance of indexes involve a trade-off between query speed and update costs. Indexes speed up retrieval at the expense of slower updates and increased storage space. diff --git a/src/data/roadmaps/sql/content/111-transactions/100-acid.md b/src/data/roadmaps/sql/content/111-transactions/100-acid.md new file mode 100644 index 000000000..617b68b89 --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/100-acid.md @@ -0,0 +1,9 @@ +# ACID + +ACID are the four properties of relational database systems that help in making sure that we are able to perform the transactions in a reliable manner. It's an acronym which refers to the presence of four properties: atomicity, consistency, isolation and durability + +Visit the following resources to learn more: + +- [What is ACID Compliant Database?](https://retool.com/blog/whats-an-acid-compliant-database/) +- [What is ACID Compliance?: Atomicity, Consistency, Isolation](https://fauna.com/blog/what-is-acid-compliance-atomicity-consistency-isolation) +- [ACID Explained: Atomic, Consistent, Isolated & Durable](https://www.youtube.com/watch?v=yaQ5YMWkxq4) diff --git a/src/data/roadmaps/sql/content/111-transactions/101-isolation-levels.md b/src/data/roadmaps/sql/content/111-transactions/101-isolation-levels.md new file mode 100644 index 000000000..8087b6246 --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/101-isolation-levels.md @@ -0,0 +1,45 @@ +# Transaction Isolation Levels + +SQL supports four transaction isolation levels, each differing in how it deals with concurrency and locks to protect the integrity of the data. Each level makes different trade-offs between consistency and performance. Here is a brief of these isolation levels with relevant SQL statements. + +1. **READ UNCOMMITTED** + This is the lowest level of isolation. One transaction may read not yet committed changes made by other transaction, also known as "Dirty Reads". Here's an example of how to set this level: + + ```sql + SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; + BEGIN TRANSACTION; + -- Execute your SQL commands here + COMMIT; + ``` + +2. **READ COMMITTED** + A transaction only sees data changes committed before it started, averting "Dirty Reads". However, it may experience "Non-repeatable Reads", i.e. if a transaction reads the same row multiple times, it might get a different result each time. Here's how to set this level: + + ```sql + SET TRANSACTION ISOLATION LEVEL READ COMMITTED; + BEGIN TRANSACTION; + -- Execute your SQL commands here + COMMIT; + ``` + +3. **REPEATABLE READ** + Here, once a transaction reads a row, any other transaction's writes (changes) onto those rows are blocked until the first transaction is finished, preventing "Non-repeatable Reads". However, "Phantom Reads" may still occur. Here's how to set this level: + + ```sql + SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; + BEGIN TRANSACTION; + -- Execute your SQL commands here + COMMIT; + ``` + +4. **SERIALIZABLE** + This is the highest level of isolation. It avoids "Dirty Reads", "Non-repeatable Reads" and "Phantom Reads". This is done by fully isolating one transaction from others: read and write locks are acquired on data that are used in a query, preventing other transactions from accessing the respective data. Here's how to set this level: + + ```sql + SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; + BEGIN TRANSACTION; + -- Execute your SQL commands here + COMMIT; + ``` + +Remember, higher levels of isolation usually provide more consistency but can potentially decrease performance due to increased waiting times for locks. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/111-transactions/102-begin.md b/src/data/roadmaps/sql/content/111-transactions/102-begin.md new file mode 100644 index 000000000..0c0492a2c --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/102-begin.md @@ -0,0 +1,43 @@ +# BEGIN + +In SQL, a transaction refers to a unit of work performed against a database. Transactions in SQL are used to ensure the integrity of the database. The keywords used in SQL to control the transactions are `BEGIN`, `COMMIT`, `ROLLBACK`. + +## BEGIN + +In the context of SQL transactions, `BEGIN` is a keyword used to start a transaction. It marks the point at which the data referenced by a connection is logically consistent. After the `BEGIN` statement, the transaction is considered to be "open" and remains so until it is committed or rolled back. + +Once you've initiated a transaction with `BEGIN`, all the subsequent SQL statements will be a part of this transaction until an explicit `COMMIT` or `ROLLBACK` is given. + +## Syntax + +The syntax to start a transaction is: +```sql +BEGIN TRANSACTION; +``` +or simply, +```sql +BEGIN; +``` +## Example + +Below is a simple example of using `BEGIN` in SQL: + +```sql +BEGIN; + +INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country) +VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway'); + +COMMIT; +``` + +In this example: +- `BEGIN;` marks the start of the transaction. +- The `INSERT` statement adds a new row of data to the `Customers` table. +- `COMMIT;` ends the transaction and permanently saves the changes made during this transaction. + +Note: If something goes wrong with one of the SQL statements within the transaction (after the `BEGIN;` statement), you can choose to `ROLLBACK` the transaction, which means canceling all the changes made in this transaction up to the point of error. + +## Conclusion + +In summary, `BEGIN` in SQL is used to start a transaction, which enables modifications done in a database to be viewed as a logically coherent occurrence. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/111-transactions/103-commit.md b/src/data/roadmaps/sql/content/111-transactions/103-commit.md new file mode 100644 index 000000000..5af2c5e7a --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/103-commit.md @@ -0,0 +1,39 @@ +# COMMIT + +The SQL COMMIT command is used to save all the modifications made by the current transaction to the database. A COMMIT command ends the current transaction and makes permanent all changes performed in the transaction. It is a way of ending your transaction and saving your changes to the database. + +After the SQL COMMIT statement is executed, it can not be rolled back, which means you can't undo the operations. COMMIT command is used when the user is satisfied with the changes made in the transaction, and these changes can now be made permanent in the database. + +## Syntax: + +```sql +COMMIT; +``` +In some databases, if AUTOCOMMIT is enabled (which is typically the default setting), then every single SQL statement is treated as a transaction and automatically committed right after it is executed. + +Example: + +Imagine you have a transaction that transfers money from Account A to Account B. The SQL might look something like this: + +```sql +START TRANSACTION; +UPDATE Account SET amount = amount - 2000 WHERE name = 'A'; +UPDATE Account SET amount = amount + 2000 WHERE name = 'B'; +COMMIT; +``` +In this transaction, $2000 is transferred from account 'A' to account 'B'. The COMMIT statement makes these changes permanent in the database. + +However, keep in mind that if there was an error during this transaction (for instance if Account A did not have enough money), you'd want to ROLLBACK the transaction, not COMMIT, to undo any changes made before the error occurred. + +## Syntax with ROLLBACK: + +```sql +START TRANSACTION; +UPDATE Account SET amount = amount - 2000 WHERE name = 'A'; +UPDATE Account SET amount = amount + 2000 WHERE name = 'B'; +IF @@ERROR != 0 + ROLLBACK +ELSE + COMMIT; +``` +Here, if @@ERROR is not 0, the transaction will be rolled back. Otherwise, the transaction will be committed. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/111-transactions/104-rollback.md b/src/data/roadmaps/sql/content/111-transactions/104-rollback.md new file mode 100644 index 000000000..99e10a6e9 --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/104-rollback.md @@ -0,0 +1,49 @@ +# ROLLBACK + +The `ROLLBACK` command is a transactional control language (TCL) instruction that undoes an unsuccessful or unsatisfactory running transaction. This process also applies to SQL Server where all individual statements in SQL Server are treated as a single atomic transaction. + +When a `ROLLBACK` command is issued, all the operations (such as Insert, Delete, Update, etc.) are undone and the database is restored to its initial state before the transaction started. + +## When to use `ROLLBACK` + +1. If the transaction is unacceptable or unsuccessful. +2. If you want to revert the unwanted changes. + +Here is a basic example: + +```sql +BEGIN TRANSACTION; + +-- This would delete all rows from the table. +DELETE FROM Employee; + +-- Oh no! That's not what I wanted. Let's roll that back. +ROLLBACK; +``` + +In this example, the `ROLLBACK` command would restore all deleted data into the `Employee` table. + +SQL also allows the usage of `SAVEPOINT`s along with the `ROLLBACK` command, which allows rolling back to a specific point in a transaction, instead of rolling back the entire transaction. + +Here is an example of using `SAVEPOINT`s: + +```sql +BEGIN TRANSACTION; + +-- Adding new employee. +INSERT INTO Employee(ID, Name) VALUES(1, 'John'); + +-- Create a savepoint to be able to roll back to this point. +SAVEPOINT SP1; + +-- Oh no! I made a mistake creating this employee. Let's roll back to the savepoint. +ROLLBACK TO SAVEPOINT SP1; + +-- Now I can try again. +INSERT INTO Employee(ID, Name) VALUES(1, 'Jack'); + +-- Commit the changes. +COMMIT; +``` + +In this example, `ROLLBACK TO SAVEPOINT SP1` would undo the first insert into the `Employee` table while preserving the state of the database as it was at the savepoint `SP1`. So, the second insert command would properly add 'Jack' in place of 'John'. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/111-transactions/105-savepoint.md b/src/data/roadmaps/sql/content/111-transactions/105-savepoint.md new file mode 100644 index 000000000..e00437244 --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/105-savepoint.md @@ -0,0 +1,60 @@ +# SAVEPOINT + +A savepoint is a way of implementing subtransactions (nested transactions) within a relational database management system by indicating a particular point within a transaction that a user can "roll back" to in case of failure. The main property of a savepoint is that it enables you to create a rollback segment within a transaction. This allows you to revert the changes made to the database after the Savepoint without having to discard the entire transaction. + +A Savepoint might be used in instances where if a particular operation fails, you would like to revert the database to the state it was in before the operation was attempted, but you do not want to give up on the entire transaction. + +## Savepoint Syntax + +The general syntax for `SAVEPOINT`: + +```sql +SAVEPOINT savepoint_name; +``` + +## Use of Savepoint + +Here is the basic usage of savepoint: + +```sql +START TRANSACTION; +INSERT INTO Table1 (Column1) VALUES ('Value1'); + +SAVEPOINT SP1; + +INSERT INTO Table1 (Column1) VALUES ('Value2'); + +ROLLBACK TO SP1; + +COMMIT; +``` + +In this example, an initial `INSERT` statement is performed before a Savepoint named `SP1` is created. Another `INSERT` statement is called and then `ROLLBACK TO SP1` is executed. This means all changes between the creation of `SP1` and `ROLLBACK TO SP1` are reverted. After that, 'COMMIT' is used to permanently store the changes made by the first `INSERT` statement. + +## Release Savepoint + +The `RELEASE SAVEPOINT` deletes a savepoint within a transaction. + +Here’s the syntax: + +```sql +RELEASE SAVEPOINT savepoint_name; +``` + +The action of releasing a savepoint removes the named savepoint from the set of savepoints of the current transaction. No changes are undone. + +## Remove Savepoint + +The `ROLLBACK TO SAVEPOINT` removes a savepoint within a transaction. + +Here’s the syntax: + +```sql +ROLLBACK TRANSACTION TO savepoint_name; +``` + +This statement rolls back a transaction to the named savepoint without terminating the transaction. + +Please note, savepoint names are not case sensitive and must obey the syntax rules of the server. + +If you found this information useful and want to learn more about topics like transactions, SQL commands, normalisation and more, consider subscribing to our mailing list. You’ll receive regular updates and exclusive content to help you become a better SQL developer. Please contact me if you have any further queries. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/111-transactions/index.md b/src/data/roadmaps/sql/content/111-transactions/index.md new file mode 100644 index 000000000..aa1e35ab3 --- /dev/null +++ b/src/data/roadmaps/sql/content/111-transactions/index.md @@ -0,0 +1,52 @@ +# Transactions + +A `transaction` in SQL is a unit of work that is performed against a database. Transactions are units or sequences of work accomplished in a logical order, whether in a manual fashion by a user or automatically by some sort of a database program. + +Transactions are used to ensure data integrity and to handle database errors while processing. SQL transactions are controlled by the following commands: + +- `BEGIN TRANSACTION` +- `COMMIT` +- `ROLLBACK` + +## BEGIN TRANSACTION + +This command is used to start a new transaction. + +```sql +BEGIN TRANSACTION; +``` + +## COMMIT + +The `COMMIT` command is the transactional command used to save changes invoked by a transaction to the database. + +```sql +COMMIT; +``` +When you commit the transaction, the changes are permanently saved in the database. + +## ROLLBACK + +The `ROLLBACK` command is the transactional command used to undo transactions that have not already been saved to the database. + +```sql +ROLLBACK; +``` + +When you roll back a transaction, all changes made since the last commit in the database are undone, and the database is rolled back to the state it was in at the last commit. + +## Transaction Example +```sql +BEGIN TRANSACTION; + +UPDATE Accounts SET Balance = Balance - 100 WHERE id = 1; +UPDATE Accounts SET Balance = Balance + 100 WHERE id = 2; + +IF @@ERROR = 0 + COMMIT; +ELSE + ROLLBACK; +``` +In this example, we are transferring 100 units from account 1 to account 2 inside a transaction. If any errors occurred during any of the update statements (captured by `@@ERROR`), the transaction is rolled back, otherwise, it is committed. + +Remember that for the transaction to be successful, all commands must execute successfully. If any command fails, the transaction fails, the database state is left unchanged and an error is returned. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/112-integrity-security/100-constraints.md b/src/data/roadmaps/sql/content/112-integrity-security/100-constraints.md new file mode 100644 index 000000000..0149de1ce --- /dev/null +++ b/src/data/roadmaps/sql/content/112-integrity-security/100-constraints.md @@ -0,0 +1,83 @@ +# Data Integrity Constraints + +SQL constraints are used to specify rules for the data in a table. They ensure the accuracy and reliability of the data within the table. If there is any violation between the constraint and the action, the action is aborted by the constraint. + +Constraints are classified into two types: column level and table level. Column level constraints apply to individual columns whereas table level constraints apply to the entire table. + +Here are the commonly used constraints: + +## 1. NOT NULL + +The `NOT NULL` constraint enforces a field to always contain a value. This means that you cannot insert a new record or update a record without adding a value to this field. + +**Example:** + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int +); +``` + +## 2. UNIQUE + +The `UNIQUE` constraint ensures that all values in a column are different, thus, prevents duplicate values in a column. + +**Example:** + +```sql +CREATE TABLE Employees ( + ID int NOT NULL UNIQUE, + Name varchar(255) NOT NULL, + Age int +); +``` + +## 3. PRIMARY KEY + +The `PRIMARY KEY` constraint uniquely identifies each record in a database table. This constraint provides uniqueness for the column or set of columns, and not null. + +**Example:** + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + PRIMARY KEY (ID) +); +``` + +## 4. FOREIGN KEY + +The `FOREIGN KEY` constraint prevents actions that would destroy links between tables. It maintains referential integrity by requiring that a value inserted into a foreign key column exists in the referenced primary key. + +**Example:** + +```sql +CREATE TABLE Orders ( + OrderID int NOT NULL, + OrderNumber int NOT NULL, + EmployeeID int, + PRIMARY KEY (OrderID), + FOREIGN KEY (EmployeeID) REFERENCES Employees(ID) +); +``` + +## 5. CHECK + +The `CHECK` constraint ensures that all values in a field satisfy a condition. It enables a condition to check the value being entered into a record. + +**Example:** + +```sql +CREATE TABLE Employees ( + ID int NOT NULL, + Name varchar(255) NOT NULL, + Age int, + CHECK (Age>=18) +); +``` + +Each constraint has its own purpose and usage, utilizing them effectively helps maintain the accuracy and integrity of the data. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/112-integrity-security/101-grant-revoke.md b/src/data/roadmaps/sql/content/112-integrity-security/101-grant-revoke.md new file mode 100644 index 000000000..ac7f48499 --- /dev/null +++ b/src/data/roadmaps/sql/content/112-integrity-security/101-grant-revoke.md @@ -0,0 +1,46 @@ +# GRANT and REVOKE + +In SQL, `GRANT` and `REVOKE` are Data Control Language (DCL) commands used for providing and removing user privileges respectively. + +## GRANT + +The `GRANT` statement allows database administrators to grant permissions or privileges on a database object to users. There are various types of privileges like SELECT, INSERT, UPDATE, DELETE, REFERENCES, ALL. + +You can use the `GRANT` statement as follows: + +```sql +GRANT privilege_name +ON object_name +TO {user_name |PUBLIC |role_name} +[WITH GRANT OPTION]; +``` + +Example: + +```sql +GRANT SELECT ON employees TO user1; +``` + +In this example, `user1` is granted permission to read/perform SELECT operations on the `employees` table. + +## REVOKE + +The `REVOKE` statement can be used when we want to revoke some or all of the privileges that were assigned earlier to a user or a group of users. The syntax for using the `REVOKE` command is similar to the `GRANT` command. + +Here's the syntax: + +```sql +REVOKE privilege_name +ON object_name +FROM {user_name |PUBLIC |role_name} +``` + +Example: + +```sql +REVOKE SELECT ON employees FROM user1; +``` + +In this example, `user1` is revoked from the permission to read/perform SELECT operations on the `employees` table. + +Permission management is an important aspect of database management, understanding, and using `GRANT` and `REVOKE` operations help in maintaining the integrity and security of your data in SQL. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/112-integrity-security/102-security-best-practices.md b/src/data/roadmaps/sql/content/112-integrity-security/102-security-best-practices.md new file mode 100644 index 000000000..a73c9220b --- /dev/null +++ b/src/data/roadmaps/sql/content/112-integrity-security/102-security-best-practices.md @@ -0,0 +1,45 @@ +# Database Security Best Practices + +Database security is key in ensuring sensitive information is kept intact and isn't exposed to a malicious or accidental breach. Here are some best practices related to SQL security: + +## 1. Least Privilege Principle + +This principle states that a user should have the minimum levels of access necessary and nothing more. For large systems, this could require a good deal of planning. + +## 2. Regular Updates + +Always keep SQL Server patched and updated to gain the benefit of the most recent security updates. + +## 3. Complex and Secure Passwords + +Passwords should be complex and frequently changed. Alongside the use of `GRANT` and `REVOKE`, this is the front line of defense. + +## 4. Limiting Remote Access + +If remote connections to the SQL server are not necessary, it is best to disable it. + +## 5. Avoid Using SQL Server Admin Account + +You should avoid using the SQL Server admin account for regular database operations to limit security risk. + +## 6. Encrypt Communication + +To protect against data sniffing, all communication between SQL Server and applications should be encrypted. + +## 7. Database Backups + +Regular database backups are crucial for data integrity if there happens to be a data loss. + +## 8. Monitoring and Auditing + +Regularly monitor and audit your database operations to keep track of who does what in your database. + +## 9. Regular Vulnerability Scanning + +Use a vulnerability scanner to assess the security posture of your SQL. + +## 10. SQL Injection + +SQL injection can be reduced by using parameterized queries or prepared statements. + +These practices can significantly improve your SQL security posture. However, remember that security is not a one-time effort, but a continuous process. Regular assessment and necessary updates are key. Remember to keep an eye on security news concerning SQL Server and regularly check for new security risks or vulnerabilities. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/112-integrity-security/index.md b/src/data/roadmaps/sql/content/112-integrity-security/index.md new file mode 100644 index 000000000..cd500cc11 --- /dev/null +++ b/src/data/roadmaps/sql/content/112-integrity-security/index.md @@ -0,0 +1,54 @@ +# Data Integrity and Security + +Integrity Security in SQL refers to the accuracy and consistency of the data in a database. It is a crucial aspect of the database that ensures the data being entered into databases follows the defined rules, preventing any damage to the main data. It comes in several forms: + +**1. Entity Integrity** + +Entity integrity ensures that there are no duplicate rows in a table. This is often managed with the help of the primary key. + +For example, consider the following SQL command to create a table. Primary Key on the EmployeeID column will ensure that every entry in this column is unique. + +```sql +CREATE TABLE Employee ( + EmployeeID int NOT NULL, + LastName varchar(255), + FirstName varchar(255), + Age int, + PRIMARY KEY (EmployeeID) +); +``` + +**2. Domain Integrity** + +Domain Integrity enforces valid entries for a given column by restricting the type, the format, or the range of possible values. + +For example, setting a specific data type and size for a column. + +```sql +CREATE TABLE Employee ( + EmployeeID int NOT NULL, + LastName varchar(50), + FirstName varchar(50), + Age int CHECK (Age>=18 and Age<=60) +); +``` + +**3. Referential Integrity** + +Referential integrity ensures that relationships between tables remain consistent. More specifically, that a foreign key in one table must always refer to the primary key in another table. + +```sql +CREATE TABLE Orders ( + OrderID int NOT NULL, + OrderNumber int NOT NULL, + EmployeeID int, + PRIMARY KEY (OrderID), + FOREIGN KEY (EmployeeID) REFERENCES Employee(EmployeeID) +); +``` +**4. User-Defined Integrity** + +User-defined integrity refers to a set of rules specified by a user, which do not belong to the entity, domain, or referential integrity. +For example, a user might define a rule that an employee's hire date must be less than 3 months in the future. + +Please note that SQL doesn't provide specific built-in functionalities to handle user-defined integrity, it depends on the code logic implemented by each application. diff --git a/src/data/roadmaps/sql/content/113-stored-procedures-functions.md b/src/data/roadmaps/sql/content/113-stored-procedures-functions.md new file mode 100644 index 000000000..a7f0802e1 --- /dev/null +++ b/src/data/roadmaps/sql/content/113-stored-procedures-functions.md @@ -0,0 +1,60 @@ +# Stored Procedures and Functions + +A SQL stored procedure is a set of SQL code that can be saved and reused. In other words, it's a precompiled object because it's compiled at a time when it's created on the database. Stored procedures can take parameters, process the tasks or query the database, and return a result. + +Here's a basic example: + +```sql +CREATE PROCEDURE getEmployeesBySalary + @minSalary int +AS +BEGIN + SELECT firstName, lastName + FROM Employees + WHERE salary > @minSalary +END +GO +``` + +To call this stored procedure, we would use: + +```sql +EXEC getEmployeesBySalary 50000 +``` + +## Functions + +A SQL function is a set of SQL statements that perform a specific task. Functions must return a value or result. We can use these functions in SELECT, INSERT, DELETE, UPDATE statements. + +There are two types of functions in SQL: + +- **Scalar functions**, which return a single value and can be used where single expressions are used. For instance: + +```sql +CREATE FUNCTION addNumbers(@a int, @b int) +RETURNS int +AS +BEGIN + RETURN @a + @b +END +``` + +- **Table-valued functions**, which return a table. They can be used in JOIN clauses as if they were a normal table. For example: + +```sql +CREATE FUNCTION getBooks (@authorID INT) +RETURNS TABLE +AS +RETURN ( + SELECT books.title, books.publicationYear + FROM books + WHERE books.authorID = @authorID +) +``` + +To call this function: + +```sql +SELECT title, publicationYear +FROM getBooks(3) +``` \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/100-indexes.md b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/100-indexes.md new file mode 100644 index 000000000..fb0fb0797 --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/100-indexes.md @@ -0,0 +1,41 @@ +# Using Indexes + +Indexes in SQL are used as a way to quicken the rate of retrieval operations on a database table. Much like the index in a book, SQL indexes allow the database program to find the data without needing to go through every row in a table and thus improves performance. + +## Types of Indexes: + +1. **Single-Column Indexes:** + +These are created based on only one table column. The syntax for creating a single column index is as follows: +``` +CREATE INDEX index_name +ON table_name (column1); +``` + +2. **Unique Indexes:** + +They ensure the data contained in a column or a combination of two or more columns is unique. Syntax to create unique index is as follows: +``` +CREATE UNIQUE INDEX index_name +ON table_name (column1, column2...); +``` + +3. **Composite Indexes:** + +These are based on two or more columns of a table. It's important to note that, the order of columns in the definition of an index is important. Syntax to create a Composite Indexes is as follows: +``` +CREATE INDEX index_name +ON table_name (column1, column2); +``` + +4. **Implicit Indexes:** + +These are indexes that are automatically created by the database server when an object is defined. For example, when a primary key is defined. + +## How Indexes Work + +SQL indexes work by storing a part of a table's data in a place where it can be accessed extremely swiftly. The index holds the column value, and the location of the record itself. This is similar to how an index in a book stores the word, and the page number on which the word can be found. + +## Considerations + +While they do provide a significant advantage, they also require additional storage and can slow down the rate of updates and inserts into a database. As such, indexes should be used judiciously, taking into consideration the nature of the data in the table and the kinds of queries that will be used. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/101-optimizing-joins.md b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/101-optimizing-joins.md new file mode 100644 index 000000000..98bdc541e --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/101-optimizing-joins.md @@ -0,0 +1,58 @@ +# Optimizing Joins + +Query optimization for joins is an essential aspect in improving the execution speed of your SQL commands and reduce the response time. Joins, particularly the ones involving multiple tables, can be quite costly in terms of database performance. Here are some methods to optimize joins in SQL: + +## 1. Minimize the Number of Tables in the Join + +Try to keep the number of tables in each join operation as low as possible. Remove any tables which are not necessary to retrieve the requested data. + +```sql +SELECT Customers.CustomerName, Orders.OrderID +FROM Customers +JOIN Orders +ON Customers.CustomerID = Orders.CustomerID +ORDER BY Customers.CustomerName; +``` + +## 2. Check the Order of Tables in the Join + +The order in which tables are joined can have a considerable impact on the execution time. As a general rule, join the tables that have the most rows last. If you are joining more than two tables, and aren’t certain of the best order, you can try different orders to see which gives the best performance. + +```sql +SELECT * +FROM Table1 -- smallest table +JOIN Table2 ON Table1.ID = Table2.ID -- larger table +JOIN Table3 ON Table1.ID = Table3.ID -- largest table +``` + +## 3. Always Use Indexes + +Using indexes helps improve the speed at which SQL can execute a join. Indexes are particularly useful if your join involves columns that are often involved in where clauses or sort operations. SQL can utilize indexes to quickly locate the rows it needs, and this can drastically improve performance. + +```sql +CREATE INDEX idx_columnname +ON table_name (column_name); +``` + +## 4. Use Subqueries + +Sometimes, it would be faster to retrieve the data in multiple steps using subqueries. In the below example, instead of joining, we are retrieving IDs using a subquery and then fetching the data using those IDs. + +```sql +SELECT column_name(s) +FROM table1 +WHERE column_name IN (SELECT column_name FROM table2); +``` + +## 5. Use Explicit JOIN Syntax + +Use of explicit syntax helps in better understanding of the relations between the tables, thus enabling the SQL execution engine to get optimized plans. + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +INNER JOIN Customers +ON Orders.CustomerID = Customers.CustomerID; +``` + +In conclusion, the optimization of joins is an art that requires some level of knowledge about database design and how SQL works under the hood. A performance-efficient SQL code needs thorough testing and trial-n-run for different scenarios. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/102-reducing-subqueries.md b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/102-reducing-subqueries.md new file mode 100644 index 000000000..215b8f3e1 --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/102-reducing-subqueries.md @@ -0,0 +1,57 @@ +# Reducing Subqueries + +SQL subqueries allow you to nest a SELECT statement inside another query. However, while this can sometimes simplify the code, the drawback is they can result in long-running queries and reduced performance. Therefore, optimizing queries often involves reducing subqueries. Two common ways to achieve this include using JOINS and 'EXISTS' clause. + +1. **JOIN:** A JOIN clause combines rows from two or more tables based on a related column. In many cases, a JOIN can replace a subquery with equivalent logic, but with improved performance. + +An example would be a scenario where you have two tables `Orders` and `Customers`, and you want to find orders made by a specific customer: + +Subquery could be: + +```sql +SELECT OrderNumber +FROM Orders +WHERE CustomerID IN ( + SELECT CustomerID + FROM Customers + WHERE CustomerName = 'John Doe' + ); +``` + +Equivalent JOIN: + +```sql +SELECT o.OrderNumber +FROM Orders o +JOIN Customers c ON o.CustomerID = c.CustomerID +WHERE c.CustomerName = 'John Doe'; +``` + +2. **EXISTS:** The EXISTS operator checks for the existence of rows returned by the subquery. Many times, a subquery can be replaced with an EXISTS clause which would greatly increase performance as EXISTS will stop processing once it hits a true condition and does not need to check all results like IN would. + +Consider you want to find all customers who have placed at least one order: + +Subquery might be: + +```sql +SELECT * +FROM Customers +WHERE CustomerID IN ( + SELECT CustomerID + FROM Orders + ); +``` + +Equivalent EXISTS use case: + +```sql +SELECT * +FROM Customers c +WHERE EXISTS ( + SELECT 1 + FROM Orders o + WHERE c.CustomerID = o.CustomerID + ); +``` + +While it's important to minimize subqueries whenever possible, there may be cases where you cannot replace a subquery, especially when dealing with correlated subqueries or complex queries where rewriting might be nontrivial or not feasible. diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/103-selective-projection.md b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/103-selective-projection.md new file mode 100644 index 000000000..0c4849137 --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/103-selective-projection.md @@ -0,0 +1,27 @@ +# Selective Projection + +Selective projection in SQL is a concept related to retrieving only specific columns from a table rather than retrieving all columns. It's one of the most basic ways to optimize your queries in SQL and make them more efficient. + +In SQL, a projection refers to the operation in which we choose certain columns (instead of all columns) from the table for our query results. If a table has numerous columns, and we only need data from a few of them, it's more efficient to only select those specific columns in the SQL query. This reduces the amount of data that needs to be scanned and fetched from the database, thereby improving performance. + +## Examples + +Let's take an example where you have a "students" table with the following columns: Id, Name, Age, Gender, Department, and City. If you only need Name and Department information, you should use a selective projection to specify only these columns in your SELECT statement: + +```sql +SELECT Name, Department +FROM students +``` + +This query returns just the Name and Department columns, rather than all fields in the students table. + +In contrast, if you used a `SELECT *` statement: + +```sql +SELECT * +FROM students +``` + +This would return all columns from the "students" table which can be inefficient if you don't need all that data. + +Selective projection can greatly optimize your SQL queries by minimizing the amount of data handled. It's especially beneficial when tables have large amounts of data and many columns, but only a subset of information is required. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/index.md b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/index.md new file mode 100644 index 000000000..2af1b0b24 --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/100-query-optimization/index.md @@ -0,0 +1,65 @@ +# Query Optimization Techniques + +SQL Query Optimization is a crucial aspect of database management, aiming to maximize the speed and efficiency of SQL queries. Optimization takes into consideration a variety of factors like the query structure, data distribution, hardware specifics, and data-indexing. + +## 1. Utilize Indexes: + +Indexes enable the database engine to quickly find records just like an index in a book helps facilitate faster information location. + +```sql +CREATE INDEX index_name +ON table_name (column1, column2, ...); +``` + +## 2. Use Joins instead of Multiple Queries: + +Multiple separate queries to retrieve data can be merged into a single JOIN query for a more efficient process. + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +INNER JOIN Customers +ON Orders.CustomerID=Customers.CustomerID; +``` + +## 3. Limit the Number of Rows: + +Only request the number of rows you need. The `LIMIT` clause reduces the number of records returned by a SQL statement. + +```sql +SELECT column FROM table +ORDER BY column DESC +LIMIT 10; +``` + +## 4. Avoid SELECT * : + +Select only the columns you need to prevent the overhead of loading unnecessary data. + +```sql +SELECT column1, column2 +FROM table; +``` + +## 5. Use WHERE instead of HAVING for Filtering: +`WHERE` clause filters records before grouping while `HAVING` filters after. Utilizing `WHERE` can optimize the query performance. + +```sql +SELECT column1, COUNT(column2) +FROM table +WHERE condition +GROUP BY column1; +``` + +## 6. If Possible Avoid the use of Subqueries: + +A subquery is a SQL query enclosed in a larger SQL query. Often they may result in complex and less optimized queries. + +```sql +SELECT column_name(s) +FROM table1 +WHERE column_name operator + (SELECT column_name(s) from table2); +``` + +Remember there's no universal optimal solution, each SQL query will have its specific optimization strategies. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/101-query-analysis.md b/src/data/roadmaps/sql/content/114-perf-optimization/101-query-analysis.md new file mode 100644 index 000000000..063f10671 --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/101-query-analysis.md @@ -0,0 +1,39 @@ +# Query Analysis Techniques + +Query analysis is a critical part of performance optimization in SQL. It involves critically examining your SQL queries to determine potential bottlenecks, unnecessary computations or data fetch operations, and areas where you can implement performance optimization techniques. + +## Explain Plan + +SQL provides an "EXPLAIN PLAN" statement that can be utilized to understand the execution plan of a query. This is used to analyze the performance of SQL commands before actually executing them. + +When running the command, the output shows the steps involved in executing the query and an estimation of the cost involved with each step. The cost is a unitless value representing the resources required to perform the operation. + +```sql +EXPLAIN PLAN FOR SELECT * FROM table_name; +``` + +## Index Usage + +Using appropriate indexes is crucial for query performance. Unnecessary full table scans can be avoided if the correct indexes are present. Even though SQL will automatically determine the appropriate index to use, it can be helpful to manually specify which index to use for complex queries. + +```sql +CREATE INDEX idx_column ON table_name(column_name); +``` + +## Join Optimization + +The order in which tables are joined can have a large impact on query performance. In general, you should join tables in a way that results in the smallest result set as early as possible. + +Look out for "Nested Loops" in your explain plan. These can be a cause of slow performance if a large number of rows are being processed. + +```sql +SELECT * +FROM table1 +INNER JOIN table2 ON table1.id = table2.id; +``` + +## Regular Performance Tests + +Regular query performance testing can catch slow queries before they become a problem. Utilizing tools that can monitor and report query performance can help you keep an eye on your database's performance. + +Also, continual analysis of the query performance should be done as your data grows. A query that performs well with a small dataset may not do so when the dataset grows. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/114-perf-optimization/index.md b/src/data/roadmaps/sql/content/114-perf-optimization/index.md new file mode 100644 index 000000000..03fcd271d --- /dev/null +++ b/src/data/roadmaps/sql/content/114-perf-optimization/index.md @@ -0,0 +1,67 @@ +# Performance Optimization + +SQL performance optimization is crucial for accelerating SQL queries and improving overall database performance. Most importantly, it ensures smooth and efficient execution of SQL statements, which can result in better application performance and user experience. + +## 1. Indexes + +Creating indexes is one of the prominent ways to optimize SQL performance. They accelerate lookup and retrieval of data from a database. + +```sql +CREATE INDEX index_name +ON table_name (column1, column2, ...); +``` +Remember, though indexes speed up data retrieval, they can slow down data modification such as `INSERT`, `UPDATE`, and `DELETE`. + +## 2. Avoid SELECT * + +Get only the required columns instead of fetching all columns using `SELECT *`. It reduces the amount of data that needs to be read from the disk. + +```sql +SELECT required_column FROM table_name; +``` + +## 3. Use Join Instead of Multiple Queries + +Using join clauses can combine rows from two or more tables in a single query based on a related column between them. This reduces the number of queries hitting the database, improving performance. + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +INNER JOIN Customers +ON Orders.CustomerID=Customers.CustomerID; +``` + +## 4. Use LIMIT + +If only a certain number of rows are necessary, use the LIMIT keyword to restrict the number of rows returned by the query. + +```sql +SELECT column FROM table LIMIT 10; +``` + +## 5. Avoid using LIKE Operator with Wildcards at the Start + +Using wildcard at the start of a query (`LIKE '%search_term'`) can lead to full table scans. + +```sql +SELECT column FROM table WHERE column LIKE 'search_term%'; +``` + +## 6. Optimize Database Schema + +Database schema involves how data is organized and should be optimized for better performance. + +## 7. Use EXPLAIN + +Many databases have 'explain plan' functionality that shows the plan of the database engine to execute the query. + +```sql +EXPLAIN SELECT * FROM table_name WHERE column = 'value'; +``` +This can give insight into performance bottlenecks like full table scans, missing indices, etc. + +## 8. Denormalization + +In some cases, it might be beneficial to denormalize the database to a certain extent to reduce complex joins and queries. Keep in mind that this is usually the last resort and may not always yield the desired results. + +Remember, each query and database is unique, so what might work in one scenario might not work in another. It is always crucial to test the queries in a controlled and isolated environment before pushing them into production. diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/100-recursive-queries.md b/src/data/roadmaps/sql/content/115-advanced-sql/100-recursive-queries.md new file mode 100644 index 000000000..8fa8a2fa0 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/100-recursive-queries.md @@ -0,0 +1,54 @@ +# Recursive Queries + +Recursive queries are advanced SQL queries used for data analysis, especially when working with hierarchical or tree-structured data. These queries are implemented using Common Table Expressions (CTEs). CTEs have the same structure as a standard SELECT statement but are prefixed with `WITH`, followed by the CTE name and an optional list of columns. + +CTEs can be recursive and non-recursive. The non-recursive CTE is a query that is executed once and then goes out of scope. + +## Recursive CTE + +A recursive CTE is a CTE that references itself. Recursive CTEs have a minimum of two queries, an anchor member (runs only once), and a recursive member (runs repeatedly). Include a UNION ALL statement between these queries. + +Here's a sample of a recursive CTE: + +```sql +WITH RECURSIVE ancestors AS ( + SELECT employee_id, manager_id, full_name + FROM employees + WHERE manager_id IS NULL + + UNION ALL + + SELECT e.employee_id, e.manager_id, e.full_name + FROM employees e + INNER JOIN ancestors a ON a.employee_id = e.manager_id +) +SELECT * FROM ancestors; +``` + +In this code snippet, the first query is the anchor member that fetches the employees with no manager. The second part is the recursive member, continuously fetching managers until none are left. + +## Syntax of Recursive CTE + +Here's the general structure of a recursive CTE: + +```sql +WITH RECURSIVE cte_name (column_list) AS ( + + -- Anchor member + SELECT column_list + FROM table_name + WHERE condition + + UNION ALL + + -- Recursive member + SELECT column_list + FROM table_name + INNER JOIN cte_name ON condition +) +SELECT * FROM cte_name; +``` + +Note: some database systems such as MySQL, PostgreSQL, and SQLite use `WITH RECURSIVE` for recursive CTEs. Others like SQL Server, Oracle, and DB2 use just `WITH`. + +Remember to be careful when setting the conditions for your recursive query to avoid infinite loops. diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/101-pivot-unpivot.md b/src/data/roadmaps/sql/content/115-advanced-sql/101-pivot-unpivot.md new file mode 100644 index 000000000..7e74f37e0 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/101-pivot-unpivot.md @@ -0,0 +1,62 @@ +# Pivot and Unpivot Operations + +## PIVOT + +The PIVOT operator is used in SQL to rotate the table data from rows to columns, essentially transforming the data into a matrix format. This operator allows you to create a crosstab view of the data, with selected columns as rows and others as columns, providing a summary view. + +Here is a general example of the syntax: + +```sql +SELECT ... +FROM ... +PIVOT (aggregate_function(column_to_aggregate) + FOR column_to_pivot + IN (list_of_values)) +``` + +__Example__: Let's assume we have a 'Sales' table with 'Year', 'Quarter' and 'Amount' columns. If we want to turn 'Quarter' values into columns, we might use: + +```sql +SELECT * FROM +( + SELECT Year, Quarter, Amount + FROM Sales +) +PIVOT +( + SUM(Amount) + FOR Quarter IN ('Q1' 'Q2' 'Q3' 'Q4') +) +``` + +This would give us each year as a row and each quarter as a column, with the total sales for each quarter in the cells. + +## UNPIVOT + +The UNPIVOT operator performs the reverse operation to PIVOT, rotating columns into rows. If the columns you're converting have a certain relationship, this can be factored into a single column instead. + +Here is a general example of the syntax: + +```sql +SELECT ... +FROM ... +UNPIVOT (column_for_values + FOR column_for_names IN (list_of_columns)) +``` + +__Example__: Conversely, if we want to transform the quarter columns back into rows from the previous 'Sales' pivot table, we would use: + +```sql +SELECT * FROM +( + SELECT Year, Q1, Q2, Q3, Q4 + FROM Sales +) +UNPIVOT +( + Amount + FOR Quarter IN (Q1, Q2, Q3, Q4) +) +``` + +This would result in each combination of year and quarter as a row, with the amount sold in that quarter as the 'Amount' column. Keep in mind, the UNPIVOTed data isn't equivalent to the original data as the original data might have had multiple rows for each year/quarter. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/100-row-number.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/100-row-number.md new file mode 100644 index 000000000..a203e9048 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/100-row-number.md @@ -0,0 +1,43 @@ +# Row_number + +**ROW_NUMBER()** is a SQL window function that assigns a unique number to each row in the result set. + +Syntax: + +```sql +ROW_NUMBER() OVER ( +[ORDER BY column_name] +) +``` + +## Features: + +- Numbers are assigned based on the `ORDER BY` clause of `ROW_NUMBER()`. +- In case of identical values in the `ORDER BY` clause, the function assigns numbers arbitrarily. +- In other words, the sequence of numbers generated by `ROW_NUMBER()` is not guaranteed to be the same for the same set of data. + +## Examples: + +**Example 1:** Basic usage of ROW_NUMBER() on a single column +```sql +SELECT + name, + ROW_NUMBER() OVER (ORDER BY name) row_number +FROM + employees; +``` +In this example, `ROW_NUMBER()` is used to assign a unique number to each row in the employees table, ordered by the employee names alphabetically. + +**Example 2:** Using ROW_NUMBER() to rank rows in each partition +```sql +SELECT + department_id, + first_name, + salary, + ROW_NUMBER() OVER ( + PARTITION BY department_id + ORDER BY salary DESC) row_number +FROM + employees; +``` +In this example, `ROW_NUMBER()` is used to rank employee salaries within each department (i.e., partitioned by `department_id`). In each department, employees with higher salaries are assigned lower row numbers. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/101-rank.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/101-rank.md new file mode 100644 index 000000000..0b136fffa --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/101-rank.md @@ -0,0 +1,50 @@ +# rank + +`RANK()` is a window function in SQL that assigns a unique rank to each distinct row within a partition of a result set. The rank of the first row within each partition is one. The `RANK()` function adds the number of tied rows to the tied rank to calculate the next rank. So the ranks may not be consecutive numbers. + +## Parameters of RANK Function + +There are no arguments for the `RANK()` function. However, since it's a window function, the function operates on a set of rows (window) defined by the `OVER` clause, which is mandatory. + +## Syntax + +The syntax of `RANK` function is: + +```sql +RANK () OVER ( + [PARTITION BY column_1, column_2,…] + ORDER BY column_3,column_4,… +) +``` + +`PARTITION BY`: This clause divides the rows into multiple groups or partitions upon which the `RANK()` function is applied. + +`ORDER BY`: This clause sorts the rows in each partition. + +If `PARTITION BY` is not specified, the function treats all rows in the result set as a single partition. + +## Examples + +Here's an example query using the `RANK()` function: + +```sql +SELECT + product_name, + brand, + RANK () OVER ( + PARTITION BY brand + ORDER BY product_name ASC +) Product_rank +FROM + products; +``` + +In this example, it generates a list of products, grouped by brand, and ranked by product_name within each brand. The `product_name` with the smallest value (alphabetically first when sorting ASC) gets a rank of 1 within its partition. + +## Important Notes +- `RANK()` function may return duplicate rankings if the column on which the function is applied contains duplicate values. +- The `RANK()` function will leave a gap and create a non-consecutive ranking if there are equal rankings (ties). +- `RANK()` function offers a very efficient way to solve top-N problems. + + +You might also be interested in looking at other similar ranking functions in SQL like `DENSE_RANK()`, `ROW_NUMBER()`, etc. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/102-dense-rank.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/102-dense-rank.md new file mode 100644 index 000000000..ea5b6fce5 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/102-dense-rank.md @@ -0,0 +1,44 @@ +# dense_rank + +`DENSE_RANK` is a window function in SQL that assigns a rank to each row within a window partition, with no gaps in the ranking numbers. + +Unlike the `RANK` function, `DENSE_RANK` does not skip any rank (positions in the order). If you have, for example, 1st, 2nd, and 2nd, the next rank listed would be 3rd when using `DENSE_RANK`, whereas it would be 4th using the `RANK` function. + +The `DENSE_RANK` function operates on a set of rows, called a window, and in that window, values are compared to each other. + +Here is a general syntax of `DENSE_RANK` function in SQL: +```sql +DENSE_RANK ( ) OVER ( + [ < partition_by_clause > ] + [ < order_by_clause > ] + ) +``` +- `partition_by_clause` - Divides the window into smaller sets or partitions. +- `order_by_clause` - Determines the order of data inside each partition to further work with the ranking functions. + +Let's say you have a table called 'Employees' with the following data: + +| ID | Name | Salary | +|---|---|---| +| 1 | John | 50000 | +| 2 | Mike | 60000 | +| 3 | Mary | 60000 | +| 4 | Alice | 55000 | + +Our task can be to rank these employees based on their salaries. The SQL query will be: + +```sql +SELECT Name, Salary, +DENSE_RANK () OVER (ORDER BY Salary Desc) AS Rank +FROM Employees +``` +When this query is run, the `DENSE_RANK` function will assign a rank to every row, with the highest salary being ranked as 1: + +| Name | Salary | Rank | +|---|---|---| +| Mike | 60000 | 1 | +| Mary | 60000 | 1 | +| Alice | 55000 | 2 | +| John | 50000 | 3 | + +This table clearly shows how the `DENSE_RANK` function provides rank without skipping any rank in case of a tie between the salaries of Mary and Mike. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/103-lead.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/103-lead.md new file mode 100644 index 000000000..eb463cafb --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/103-lead.md @@ -0,0 +1,34 @@ +# lead + +In SQL, the `LEAD` function is a kind of window function that allows you to look at a row after a certain row, and use its value in calculations. `LEAD` function returns the value from the next row (or a subsequent row) of the current row in the table. + +## Usage + +The `LEAD` function takes three arguments: + +1. `value_expression` - the column or expression whose next value will be returned. +2. `offset` - determines how many rows ahead to retrieve the value from. If it's omitted, then its default value is 1. +3. `default_value` - the value returned when the `LEAD` function navigates past the last row. If it's omitted, it returns NULL. + +The syntax of the `LEAD` function is as follows: + +```sql +LEAD(value_expression, [offset], [default_value]) OVER ([PARTITION BY partition_expression] ORDER BY sort_expression [ASC | DESC]) +``` + +## Example + +Consider a simple example where you have a "sales" table and you want to compare each monthly sale with the sale of the next month. + +```sql +SELECT + month, + sale, + LEAD(sale) OVER (ORDER BY month) NextMonthSale +FROM + sales; +``` + +This SQL command will give an output where each row displays the sale of the current month and the sale amount of the next month. + +Please note that 'LEAD' function might return 'NULL' if there are no subsequent rows in window frame to fetch. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/104-lag.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/104-lag.md new file mode 100644 index 000000000..2de9db2c4 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/104-lag.md @@ -0,0 +1,50 @@ +# lag + +`LAG` is a window function provided by SQL that allows us to fetch data from a previous row in the same result set without using a self-join. This function is commonly used in data analysis, for instance, comparing sales in a certain period with sales in a previous period. + +The general syntax for using the `LAG` function is as follows: + +```sql +LAG (expression [, offset [, default]]) +OVER ( + [PARTITION BY partition_expression, ... ] + ORDER BY sort_expression [ASC | DESC], ... +) +``` + +Let's break down this syntax: + +- `expression`: This is the value to return from a previous row. If you specify multiple expressions, `LAG` treats them as a single compound expression. +- `offset`: This is an optional section where you specify the number of steps to reachback. By default, the `offset` is 1, meaning that it gets the value from a previous row. +- `default`: This is another optional section where you define a value to return if the `LAG` function accesses beyond the scope of partition. By default, it returns NULL. + +## Example + +Suppose we have the following 'sales' table: + +| Year | Sales | +| ---- | ----- | +| 2017 | 200 | +| 2018 | 250 | +| 2019 | 300 | +| 2020 | 350 | + +You'd like to compare the sales of each year to the sales of the previous year. Here's how you can do it using the `LAG` function: + +```sql +SELECT Year, + Sales, + LAG(Sales) OVER (ORDER BY Year) AS PrevYearSales +FROM sales; +``` + +This should produce: + +| Year | Sales | PrevYearSales | +| ---- | ----- | ------------- | +| 2017 | 200 | NULL | +| 2018 | 250 | 200 | +| 2019 | 300 | 250 | +| 2020 | 350 | 300 | + +In this example, `LAG` fetched the sales of the previous year ordered by the 'Year' column. The sales in 2017 do not have a previous year, so `LAG` returns NULL. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/index.md b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/index.md new file mode 100644 index 000000000..d10b3e724 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/102-window-functions/index.md @@ -0,0 +1,44 @@ +# Window Functions + +SQL Window functions enable you perform calculations on a set of rows related to the current row. This set of rows is known as a 'window', hence 'Window Functions'. + +These are termed so because they perform a calculation across a set of rows which are related to the current row - somewhat like a sliding window. + +There are four types of window functions in SQL: + +- **Aggregate functions:** These functions compute a single output value for a group of input values (like averages, sums). + +```sql +SELECT department, salary, +AVG(salary) OVER (PARTITION BY department) as avg_departmental_salary +FROM employee; +``` + +- **Ranking functions:** These functions allocate a unique rank to each row within each window partition. + +```sql +SELECT department, salary, +RANK() OVER (PARTITION BY department ORDER BY salary DESC) as salary_rank +FROM employee; +``` + +- **Value functions:** These functions provide information about the window partition or the row's position within it, for example - `FIRST_VALUE`, `LAST_VALUE`, `NTH_VALUE`. + +```sql +SELECT department, salary, +FIRST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary DESC) as highest_salary +FROM employee; +``` + +- **Offset functions:** The offset functions provide a way of accessing data from another row in the same result set without joining the table to itself. They can answer questions concerning the value on the row before or after the current row, for example - `LEAD`, `LAG`. + +```sql +SELECT department, salary, +LAG(salary) OVER (PARTITION BY department ORDER BY salary) as previous_salary, +LEAD(salary) OVER (PARTITION BY department ORDER BY salary) as next_salary +FROM employee; +``` + +In using window functions, the `OVER` clause defines the windows or group of rows for function to consider, `PARTITION BY` breaks up the window by a specific column(s), and `ORDER BY` orders rows within the window. + +It's important to note that SQL window functions do not cause rows to become grouped into a single output row like aggregate methods do. Therefore, they do not reduce the number of rows returned by the query, each row maintains its individual identity. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/103-ctes.md b/src/data/roadmaps/sql/content/115-advanced-sql/103-ctes.md new file mode 100644 index 000000000..7debfca5e --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/103-ctes.md @@ -0,0 +1,59 @@ +# CTEs (Common Table Expressions) + +CTEs or Common Table Expressions are a type of temporary result set that are defined within the execution scope of a single SQL statement. They act like a temporary view for a single query, and they are typically used to simplify subqueries and improve readability. + +## Syntax + +Here is the basic syntax of how to use a CTE in SQL: + +```sql +WITH CTE_Name AS +( + SQL Query +) +SELECT * FROM CTE_Name +``` + +In this syntax, the "WITH" keyword is used to create a CTE. The SQL query inside the parentheses is the query that creates the CTE. The final SELECT statement is used to query the data from the CTE. + +## Basic Usage + +An example of how to use a CTE is demonstrated below: + +```sql +WITH Sales_CTE (SalesPersonID, NumberOfOrders) +AS +( + SELECT SalesPersonID, COUNT(OrderID) + FROM SalesOrderHeader + GROUP BY SalesPersonID +) +SELECT E.EmployeeID, E.FirstName, E.LastName, S.NumberOfOrders +FROM Employee E +JOIN Sales_CTE S +ON E.EmployeeID = S.SalesPersonID +ORDER BY S.NumberOfOrders DESC; +``` + +In this example, the CTE groups sales data by `SalesPersonID` and then joins this with the `Employee` table based on the `EmployeeID` to get the corresponding employee details. + +## Recursive CTEs + +SQL also supports recursive CTEs, which are CTEs that reference themselves. Recursive CTEs are generally used to solve problems that require iteration, such as traversing hierarchies. Here's an example: + +```sql +WITH Recursive_CTE AS +( + SELECT EmployeeID, ManagerID, FirstName + FROM Employee + WHERE ManagerID IS NULL + UNION ALL + SELECT E.EmployeeID, E.ManagerID, E.FirstName + FROM Employee E + INNER JOIN Recursive_CTE RCTE + ON E.ManagerID = RCTE.EmployeeID +) +SELECT * FROM Recursive_CTE; +``` + +In the example above, the CTE starts with the employees who have no manager (`ManagerID IS NULL`). Then it recursively adds employees who are managed by the employees already in the CTE. The result is a list of all employees in the company, hierarchically organized by manager. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/104-dynamic-sql.md b/src/data/roadmaps/sql/content/115-advanced-sql/104-dynamic-sql.md new file mode 100644 index 000000000..73b527f0d --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/104-dynamic-sql.md @@ -0,0 +1,50 @@ +# Dynamic SQL + +**Dynamic SQL** + +Dynamic SQL is a programming method that allows you to build SQL statements dynamically at runtime. It allows you to create more flexible and adaptable applications because you can manipulate the SQL statements on the fly, in response to inputs or changing conditions. + +Consider an application where a user can choose multiple search conditions from a range of choices. You might not know how many conditions the user will choose, or what they'll be until runtime. With static SQL, you would have to include a large number of potential search conditions in your WHERE clause. With dynamic SQL, you can build the search string based on the user's actual choices. + +**Executing Dynamic SQL** + +There are two ways to execute dynamic SQL: + +1. `EXECUTE IMMEDIATE` statement +2. `OPEN-FOR, FETCH, CLOSE` statements + + +**Code Examples** + +1. Using `EXECUTE IMMEDIATE`: + +Here, a table name is passed as a variable to a PL/SQL block. The block concatenates the variable into a DELETE statement, which is executed dynamically. + +```sql +DECLARE + table_name VARCHAR(30) := 'employees'; + sql_stmt VARCHAR(100); +BEGIN + sql_stmt := 'DELETE FROM ' || table_name; + EXECUTE IMMEDIATE sql_stmt; +END; +``` + +2. Using `OPEN-FOR, FETCH, CLOSE` + +In this example, a dynamic SQL query is being built and executed using the `OPEN-FOR, FETCH, CLOSE` statements. + +```sql +DECLARE + sql_stmt VARCHAR2(1000); + emp_id NUMBER(4) := 7566; + emp_rec emp%ROWTYPE; +BEGIN + sql_stmt := 'SELECT * FROM emp WHERE empno = :id'; + OPEN emp_cv FOR sql_stmt USING emp_id; + FETCH emp_cv INTO emp_rec; + CLOSE emp_cv; +END; +``` + +Note that while the use of Dynamic SQL offers greater flexibility, it also comes with potential security risks such as SQL Injection, and should be used judiciously. Always validate and sanitize inputs when building dynamic queries. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/115-advanced-sql/index.md b/src/data/roadmaps/sql/content/115-advanced-sql/index.md new file mode 100644 index 000000000..04d5ee674 --- /dev/null +++ b/src/data/roadmaps/sql/content/115-advanced-sql/index.md @@ -0,0 +1,74 @@ +# Advanced SQL Concepts + +Advanced SQL commands offer powerful functionality that allow you to conduct complex queries and operations on your database. These include operations like Stored Procedures, Triggers, Views, and more. + +## Stored Procedures + +A stored procedure is a prepared SQL code that you save, so the code can be reused over and over again. They are particularly useful when repetitive tasks need to be performed, with less client-server communication. + +```sql +CREATE PROCEDURE procedure_name +AS +sql_statement +GO; +``` + +## Triggers + +A Trigger is a SQL procedure that initiates an action when an event (INSERT, DELETE, UPDATE) occurs. Triggers are useful for maintaining integrity in the database. Triggers can also be used to log historical data. + +```sql +CREATE TRIGGER trigger_name +ON table_name +FOR INSERT, UPDATE, DELETE +AS +-- SQL Statements +``` + +## Views + +A view is a virtual table based on the result-set of an SQL statement. It allows you to view data that is derived from other tables. A view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database. + +```sql +CREATE VIEW view_name AS +SELECT column1, column2, ... +FROM table_name +WHERE condition; +``` + +## JOINs + +JOINs are used to combine rows from two or more tables, based on a related column between them. Types include INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN. + +```sql +SELECT Orders.OrderID, Customers.CustomerName +FROM Orders +INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID; +``` + +## Subqueries + +A subquery is a query that is embedded in the WHERE or HAVING clause of another SQL query. Subqueries can return individual values or a list of records. + +```sql +SELECT column_name [, column_name ] +FROM table1 [, table2 ] +WHERE column_name OPERATOR + (SELECT column_name [, column_name ] + FROM table1 [, table2 ] + [WHERE]) +``` + +## Set Operators + +Set operators allow the results of multiple queries to be combined into a single result set. The UNION, UNION ALL, INTERSECT, and MINUS operators are some of the set operators. + +```sql +SELECT column_name(s) FROM table1 +UNION +SELECT column_name(s) FROM table2; +``` + +Note: Make sure to adjust the code examples given above according to your specific use case. In some cases, you may also need to adjust them according to the syntax of the specific SQL variant that you are using. + +Also, it's important to note that these are some of the many advanced SQL topics. There are others like Window functions, CTEs, Pivoting and more. Another important area is working with different database systems as each system (like MySQL, PostgreSQL, etc.) has its own specific set of features and syntax. \ No newline at end of file diff --git a/src/data/roadmaps/sql/content/index.md b/src/data/roadmaps/sql/content/index.md new file mode 100644 index 000000000..4e768b56d --- /dev/null +++ b/src/data/roadmaps/sql/content/index.md @@ -0,0 +1 @@ +# \ No newline at end of file diff --git a/src/data/roadmaps/sql/sql.json b/src/data/roadmaps/sql/sql.json index e93df9033..fe928e1e5 100644 --- a/src/data/roadmaps/sql/sql.json +++ b/src/data/roadmaps/sql/sql.json @@ -529,7 +529,7 @@ "x": "1211", "y": "503", "properties": { - "controlName": "102-introduction:postgresql-vs-others" + "controlName": "102-introduction:sql-vs-nosql" }, "children": { "controls": { @@ -2258,7 +2258,7 @@ "x": "868", "y": "495", "properties": { - "controlName": "100-intro" + "controlName": "100-introduction" }, "children": { "controls": {