From 3481cea1004c49bff80ce6bad52a782816da8aac Mon Sep 17 00:00:00 2001 From: heumsi Date: Fri, 29 Dec 2023 07:26:13 +0000 Subject: [PATCH] Auto deploy from Github Actions --- 404.html | 25 + assets/css/0.styles.177fd922.css | 1 + assets/img/search.83621669.svg | 1 + assets/js/10.e7fb4c80.js | 1 + assets/js/11.051ae6e1.js | 1 + assets/js/12.7b93e986.js | 1 + assets/js/13.8d014a70.js | 1 + assets/js/14.138cd924.js | 1 + assets/js/15.dca0d300.js | 1 + assets/js/16.69771a0f.js | 1 + assets/js/17.66ba2d35.js | 1 + assets/js/18.760e3a59.js | 1 + assets/js/19.7b4a8a4e.js | 1 + assets/js/2.98979e96.js | 1 + assets/js/20.adec2767.js | 1 + assets/js/21.c59b443d.js | 1 + assets/js/22.f84628fa.js | 1 + assets/js/23.2c4a7cf3.js | 1 + assets/js/24.7785bb30.js | 1 + assets/js/25.dc95a31e.js | 1 + assets/js/26.a287ef6a.js | 1 + assets/js/27.a111ddcb.js | 1 + assets/js/28.b809fce0.js | 1 + assets/js/29.7029d8fa.js | 1 + assets/js/3.2e213720.js | 1 + assets/js/30.b93101cb.js | 1 + assets/js/31.363734c1.js | 1 + assets/js/4.51c0545f.js | 1 + assets/js/5.220df36c.js | 1 + assets/js/6.345e52dd.js | 1 + assets/js/7.a15a95f4.js | 1 + assets/js/8.006f2d84.js | 1 + assets/js/9.7948c093.js | 1 + assets/js/app.8473826e.js | 15 + en/index.html | 43 ++ en/tutorial/1. Tutorial Overview.html | 45 ++ en/tutorial/2. Setting Up a Connection.html | 50 ++ ...3. Executing Transactions and Queries.html | 146 ++++ .../4. Working with Database Metadata.html | 161 +++++ ...5.1. Querying Rows Using Core and ORM.html | 608 +++++++++++++++++ .../5.2. Inserting Rows Using Core.html | 107 +++ ...odifying and Deleting Rows Using Core.html | 150 ++++ .../6. Manipulating Data Using ORM.html | 206 ++++++ ...orking with Related Objects Using ORM.html | 357 ++++++++++ en/tutorial/index.html | 39 ++ index.html | 43 ++ sitemap.xml | 1 + ...354\226\274 \352\260\234\354\232\224.html" | 45 ++ ...\354\240\225\355\225\230\352\270\260.html" | 50 ++ ...\355\226\211\355\225\230\352\270\260.html" | 146 ++++ ...\354\227\205\355\225\230\352\270\260.html" | 161 +++++ ...\355\232\214\355\225\230\352\270\260.html" | 641 ++++++++++++++++++ ...\354\236\205\355\225\230\352\270\260.html" | 106 +++ ...\354\240\234\355\225\230\352\270\260.html" | 150 ++++ ...\354\236\221\355\225\230\352\270\260.html" | 207 ++++++ ...\354\227\205\355\225\230\352\270\260.html" | 373 ++++++++++ tutorial/index.html | 39 ++ 57 files changed, 3946 insertions(+) create mode 100644 404.html create mode 100644 assets/css/0.styles.177fd922.css create mode 100644 assets/img/search.83621669.svg create mode 100644 assets/js/10.e7fb4c80.js create mode 100644 assets/js/11.051ae6e1.js create mode 100644 assets/js/12.7b93e986.js create mode 100644 assets/js/13.8d014a70.js create mode 100644 assets/js/14.138cd924.js create mode 100644 assets/js/15.dca0d300.js create mode 100644 assets/js/16.69771a0f.js create mode 100644 assets/js/17.66ba2d35.js create mode 100644 assets/js/18.760e3a59.js create mode 100644 assets/js/19.7b4a8a4e.js create mode 100644 assets/js/2.98979e96.js create mode 100644 assets/js/20.adec2767.js create mode 100644 assets/js/21.c59b443d.js create mode 100644 assets/js/22.f84628fa.js create mode 100644 assets/js/23.2c4a7cf3.js create mode 100644 assets/js/24.7785bb30.js create mode 100644 assets/js/25.dc95a31e.js create mode 100644 assets/js/26.a287ef6a.js create mode 100644 assets/js/27.a111ddcb.js create mode 100644 assets/js/28.b809fce0.js create mode 100644 assets/js/29.7029d8fa.js create mode 100644 assets/js/3.2e213720.js create mode 100644 assets/js/30.b93101cb.js create mode 100644 assets/js/31.363734c1.js create mode 100644 assets/js/4.51c0545f.js create mode 100644 assets/js/5.220df36c.js create mode 100644 assets/js/6.345e52dd.js create mode 100644 assets/js/7.a15a95f4.js create mode 100644 assets/js/8.006f2d84.js create mode 100644 assets/js/9.7948c093.js create mode 100644 assets/js/app.8473826e.js create mode 100644 en/index.html create mode 100644 en/tutorial/1. Tutorial Overview.html create mode 100644 en/tutorial/2. Setting Up a Connection.html create mode 100644 en/tutorial/3. Executing Transactions and Queries.html create mode 100644 en/tutorial/4. Working with Database Metadata.html create mode 100644 en/tutorial/5.1. Querying Rows Using Core and ORM.html create mode 100644 en/tutorial/5.2. Inserting Rows Using Core.html create mode 100644 en/tutorial/5.3. Modifying and Deleting Rows Using Core.html create mode 100644 en/tutorial/6. Manipulating Data Using ORM.html create mode 100644 en/tutorial/7. Working with Related Objects Using ORM.html create mode 100644 en/tutorial/index.html create mode 100644 index.html create mode 100644 sitemap.xml create mode 100644 "tutorial/1. \355\212\234\355\206\240\353\246\254\354\226\274 \352\260\234\354\232\224.html" create mode 100644 "tutorial/2. \354\227\260\352\262\260 \354\204\244\354\240\225\355\225\230\352\270\260.html" create mode 100644 "tutorial/3. \355\212\270\353\236\234\354\236\255\354\205\230\352\263\274 \354\277\274\353\246\254 \354\213\244\355\226\211\355\225\230\352\270\260.html" create mode 100644 "tutorial/4. \353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244 \353\251\224\355\203\200\353\215\260\354\235\264\355\204\260\353\241\234 \354\236\221\354\227\205\355\225\230\352\270\260.html" create mode 100644 "tutorial/5.1. Core\354\231\200 ORM \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\241\260\355\232\214\355\225\230\352\270\260.html" create mode 100644 "tutorial/5.2. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\202\275\354\236\205\355\225\230\352\270\260.html" create mode 100644 "tutorial/5.3. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\210\230\354\240\225 \353\260\217 \354\202\255\354\240\234\355\225\230\352\270\260.html" create mode 100644 "tutorial/6. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \353\215\260\354\235\264\355\204\260 \354\241\260\354\236\221\355\225\230\352\270\260.html" create mode 100644 "tutorial/7. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \352\264\200\353\240\250 \352\260\234\354\262\264 \354\236\221\354\227\205\355\225\230\352\270\260.html" create mode 100644 tutorial/index.html diff --git a/404.html b/404.html new file mode 100644 index 0000000..97c34a8 --- /dev/null +++ b/404.html @@ -0,0 +1,25 @@ + + + + + + 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

404

Looks like we've got some broken links.
+ Take me home. +
+ + + diff --git a/assets/css/0.styles.177fd922.css b/assets/css/0.styles.177fd922.css new file mode 100644 index 0000000..84510f9 --- /dev/null +++ b/assets/css/0.styles.177fd922.css @@ -0,0 +1 @@ +code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.home .hero img{max-width:450px!important}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/sqlalchemy-for-pythonist/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983} \ No newline at end of file diff --git a/assets/img/search.83621669.svg b/assets/img/search.83621669.svg new file mode 100644 index 0000000..03d8391 --- /dev/null +++ b/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/assets/js/10.e7fb4c80.js b/assets/js/10.e7fb4c80.js new file mode 100644 index 0000000..80218a4 --- /dev/null +++ b/assets/js/10.e7fb4c80.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{406:function(t,e,n){"use strict";n.r(e);var s=n(56),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/11.051ae6e1.js b/assets/js/11.051ae6e1.js new file mode 100644 index 0000000..8452358 --- /dev/null +++ b/assets/js/11.051ae6e1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{407:function(t,a,e){"use strict";e.r(a);var s=e(56),r=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"tutorial-overview"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#tutorial-overview"}},[t._v("#")]),t._v(" Tutorial Overview")]),t._v(" "),e("br"),t._v(" "),e("h2",{attrs:{id:"overview"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#overview"}},[t._v("#")]),t._v(" Overview")]),t._v(" "),e("p",[t._v("SQLAlchemy is a library in Python that facilitates the connection to databases and the use of ORM (Object-Relational Mapping)."),e("br"),t._v("\nFor instance, you can execute specific queries in your code and perform a series of operations in the database through ORM objects.")]),t._v(" "),e("br"),t._v(" "),e("h2",{attrs:{id:"installation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[t._v("#")]),t._v(" Installation")]),t._v(" "),e("p",[t._v("SQLAlchemy can be installed as follows:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ pip "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" sqlalchemy\n")])])]),e("p",[t._v("The version being used is as follows:")]),t._v(" "),e("div",{staticClass:"language-python extra-class"},[e("pre",{pre:!0,attrs:{class:"language-python"}},[e("code",[e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" sqlalchemy\n"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sqlalchemy"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__version__ \n"),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.4")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v(".20")]),t._v("\n")])])]),e("br"),t._v(" "),e("h2",{attrs:{id:"offerings"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#offerings"}},[t._v("#")]),t._v(" Offerings")]),t._v(" "),e("p",[t._v("SQLAlchemy is offered in the following two ways:")]),t._v(" "),e("ul",[e("li",[e("strong",[t._v("Core")]),t._v(" "),e("ul",[e("li",[t._v("This is the database toolkit and the foundational architecture of SQLAlchemy.")]),t._v(" "),e("li",[t._v("It manages connections to databases, interacts with database queries and results, and provides tools to programmatically compose SQL statements.")])])]),t._v(" "),e("li",[e("strong",[t._v("ORM")]),t._v(" "),e("ul",[e("li",[t._v("Built on top of Core, it provides optional "),e("strong",[t._v("ORM")]),t._v(" (Object-Relational Mapping) features.")])])])]),t._v(" "),e("p",[t._v("It is generally recommended to understand Core first before using ORM."),e("br"),t._v("\nThis tutorial will start by explaining Core.")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/12.7b93e986.js b/assets/js/12.7b93e986.js new file mode 100644 index 0000000..cfec08b --- /dev/null +++ b/assets/js/12.7b93e986.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{408:function(t,e,a){"use strict";a.r(e);var s=a(56),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"setting-up-a-connection"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-a-connection"}},[t._v("#")]),t._v(" Setting up a Connection")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"connecting-to-a-database"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#connecting-to-a-database"}},[t._v("#")]),t._v(" Connecting to a Database")]),t._v(" "),a("p",[t._v("Let's try connecting to SQLite, a relatively lightweight database."),a("br"),t._v("\nYou can do it as follows:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" create_engine\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" engine "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" create_engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sqlite+pysqlite:///:memory:"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" echo"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" future"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("ul",[a("li",[t._v("Use the "),a("code",[t._v("sqlalchemy.create_engine")]),t._v(" function to create an "),a("strong",[t._v("'engine'")]),t._v(" that establishes a connection to the database.")]),t._v(" "),a("li",[t._v("The first argument is a "),a("strong",[a("code",[t._v("string URL")])]),t._v(".\n"),a("ul",[a("li",[t._v("Typically, the "),a("code",[t._v("string URL")]),t._v(" is structured as "),a("code",[t._v("dialect+driver://username:password@host:port/database")]),t._v(".\n"),a("ul",[a("li",[t._v("If you don't specify a "),a("code",[t._v("driver")]),t._v(", SQLAlchemy's default settings will be used.")])])]),t._v(" "),a("li",[t._v("Here, "),a("code",[t._v("sqlite+pysqlite:///test.db")]),t._v(" is the "),a("code",[t._v("string URL")]),t._v(".\n"),a("ul",[a("li",[t._v("For "),a("code",[t._v("sqlite")]),t._v(", the format follows "),a("code",[t._v("sqlite:///")]),t._v(".")])])])])]),t._v(" "),a("li",[t._v("From the string URL "),a("code",[t._v("sqlite:///test.db")]),t._v(", we can understand the following information:\n"),a("ul",[a("li",[a("strong",[t._v("Which database")]),t._v(" to use ("),a("code",[t._v("dialect")]),t._v(", in this case, "),a("code",[t._v("sqlite")]),t._v(")")]),t._v(" "),a("li",[a("strong",[t._v("Which database API")]),t._v(" (the driver interacting with the database) to use (in this case, "),a("code",[t._v("pysqlite")]),t._v(")")]),t._v(" "),a("li",[a("strong",[t._v("How to find")]),t._v(" the database (in this case, it uses the in-memory feature provided by "),a("code",[t._v("sqlite")]),t._v(")")])])]),t._v(" "),a("li",[t._v("Setting the "),a("code",[t._v("echo")]),t._v(" parameter to "),a("code",[t._v("True")]),t._v(" prints all executed SQL.")])]),t._v(" "),a("p",[t._v("Creating an engine doesn't yet attempt an actual connection. The real connection occurs only when a request to perform an operation on the database is received for the first time.")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/13.8d014a70.js b/assets/js/13.8d014a70.js new file mode 100644 index 0000000..98fdaf9 --- /dev/null +++ b/assets/js/13.8d014a70.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{409:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"executing-transactions-and-queries"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#executing-transactions-and-queries"}},[t._v("#")]),t._v(" Executing Transactions and Queries")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"obtaining-connection"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#obtaining-connection"}},[t._v("#")]),t._v(" Obtaining connection")]),t._v(" "),a("p",[t._v("You can connect to the database and execute a query as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" text\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"select 'hello world'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'hello world'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("ul",[a("li",[t._v("Obtain a "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Connection")]),a("OutboundLink")],1),t._v(" object through "),a("code",[t._v("engine.connect()")]),t._v(" and store it in "),a("code",[t._v("conn")]),t._v(".\n"),a("ul",[a("li",[t._v("This "),a("code",[t._v("Connection")]),t._v(" object allows you to interact with the database.")]),t._v(" "),a("li",[t._v("The "),a("code",[t._v("with")]),t._v(" statement becomes a single transaction unit.")])])]),t._v(" "),a("li",[a("strong",[t._v("Transactions are not committed automatically.")]),t._v(" "),a("ul",[a("li",[t._v("You have to invoke the "),a("code",[t._v("Connection.commit()")]),t._v(" to commit changes.")])])])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"committing-changes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#committing-changes"}},[t._v("#")]),t._v(" Committing Changes")]),t._v(" "),a("p",[t._v("Obtaining a connection, initiating a transaction, and interacting with the database "),a("strong",[t._v("do not automatically commit")]),t._v(" changes.")]),t._v(" "),a("p",[t._v("To commit the change, you need to call "),a("code",[t._v("Connection.commit()")]),t._v(" as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# DDL - Creating the table")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"CREATE TABLE some_table (x int, y int)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# DML - Inserting data into the table")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# TCL - Commiting changes.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("When you run the code above, you'll see the following result below.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BEGIN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CREATE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("TABLE")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COMMIT")]),t._v("\n")])])]),a("p",[t._v("You can also automatically commit at the end of a transaction using "),a("strong",[a("code",[t._v("Engine.begin()")])]),t._v(" and "),a("code",[t._v("with")]),t._v(" statement.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("begin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Transaction commits automatically when the execution is done.")]),t._v("\n")])])]),a("p",[t._v("Executing the code above will yield the following results.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BEGIN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COMMIT")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"command-line-execution-basics"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#command-line-execution-basics"}},[t._v("#")]),t._v(" Command Line Execution Basics")]),t._v(" "),a("p",[t._v("You can execute queries and retrieve results as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# conn.execute() initializes the result in an object named `result`.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n")])])]),a("ul",[a("li",[t._v("The "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Result",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Result")]),a("OutboundLink")],1),t._v(" object is the object that "),a("strong",[t._v('holds the "query result"')]),t._v(" returned by "),a("code",[t._v("conn.execute()")]),t._v(".\n"),a("ul",[a("li",[t._v("You can see what features it provides by clicking on the link.")]),t._v(" "),a("li",[t._v("For instance, you can receive "),a("em",[t._v("a list")]),t._v(" of Row objects using "),a("code",[t._v("Result.all()")]),t._v(".")])])])]),t._v(" "),a("blockquote",[a("p",[t._v("cf. Both "),a("code",[t._v("Result")]),t._v(" and "),a("code",[t._v("Row")]),t._v(" are objects provided by SQLAlchemy.")])]),t._v(" "),a("p",[t._v("You can access each row using the "),a("code",[t._v("Result")]),t._v(" object as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[t._v("result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select x, y from some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Accessing the tuple.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ...")]),t._v("\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Accessing the value by using integer index.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Accessing the value by using a name of the property.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n y "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Accessing the value by using a mapping access.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" dict_row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mappings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dict_row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'x'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n y "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dict_row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'y'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"passing-parameters-to-your-query"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#passing-parameters-to-your-query"}},[t._v("#")]),t._v(" Passing parameters to your query")]),t._v(" "),a("p",[t._v("You can pass a parameter to a query as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table WHERE y > :y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Receive in colon format (`:`).")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Pass by `dict`.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n")])])]),a("p",[t._v("You can also send multiple parameters like this.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Pass by `List[dict]``")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("The above code executes the following query.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"executing-orm-by-using-session"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#executing-orm-by-using-session"}},[t._v("#")]),t._v(" Executing ORM by using "),a("code",[t._v("Session")])]),t._v(" "),a("p",[t._v("From now on, let's execute the query using "),a("code",[t._v("Session")]),t._v(" provided by the "),a("code",[t._v("ORM")]),t._v(", instead of the "),a("code",[t._v("Connection")]),t._v(" object.\nYou can do it as follows:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Session\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("bindparams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Pass an instance of the Engine object to the Session object")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# to get an instance that can interact with the database.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Executing the query using Session.execute().")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Like "),a("code",[t._v("Connection")]),t._v(", "),a("code",[t._v("Session")]),t._v(" also "),a("strong",[t._v("does not automatically commit")]),t._v(" upon closing. To commit, you need to "),a("em",[t._v("explicitly call")]),t._v(" "),a("code",[t._v("Session.commit()")]),t._v(" as follows:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"UPDATE some_table SET y=:y WHERE x=:x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You have to call `commit()` explicitly.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/14.138cd924.js b/assets/js/14.138cd924.js new file mode 100644 index 0000000..f003e92 --- /dev/null +++ b/assets/js/14.138cd924.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{410:function(t,a,s){"use strict";s.r(a);var n=s(56),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"working-with-database-metadata"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#working-with-database-metadata"}},[t._v("#")]),t._v(" Working with Database Metadata")]),t._v(" "),s("br"),t._v(" "),s("p",[t._v("SQLAlchemy Core and ORM were created to allow Python objects to be used like tables and columns in a database. These can be used as "),s("em",[t._v("database metadata")]),t._v(".")]),t._v(" "),s("blockquote",[s("p",[t._v("Metadata describes data that describes other data. Here, "),s("strong",[t._v("metadata refers to configured tables, columns, constraints, and other object information")]),t._v(".")])]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"creating-a-table-object-and-add-it-to-your-metadata"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-table-object-and-add-it-to-your-metadata"}},[t._v("#")]),t._v(" Creating a table object and add it to your metadata")]),t._v(" "),s("p",[t._v("In relational databases, tables are created via queries, but in SQLAlchemy, tables can be created through Python objects.\nTo start with SQLAlchemy Expression Language, you need to create a "),s("code",[t._v("Table")]),t._v(" object for the database table you want to use.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" MetaData\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# An object that will hold the meta information for the tables.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" metadata "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MetaData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The name of the table that will be stored in the database.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The columns that will go into this table.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("ul",[s("li",[s("p",[t._v("You can create database tables using the "),s("code",[t._v("Table")]),t._v(" object.")])]),t._v(" "),s("li",[s("p",[t._v("Columns of the table are implemented using "),s("code",[t._v("Column")]),t._v(".")]),t._v(" "),s("ul",[s("li",[t._v("By default, it defines like "),s("code",[t._v("Column(column name, data type)")]),t._v(".")])])]),t._v(" "),s("li",[s("p",[t._v("After creating a "),s("code",[t._v("Table")]),t._v(" instance, you can know the created column information as follows:")])])]),t._v(" "),s("div",{staticClass:"language-Python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\nColumn"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("keys"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("br"),t._v(" "),s("h2",{attrs:{id:"declaring-simple-constraints"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#declaring-simple-constraints"}},[t._v("#")]),t._v(" Declaring Simple Constraints")]),t._v(" "),s("p",[t._v("We saw the "),s("code",[t._v("Column('id', Integer, primary_key=True)")]),t._v(" statement in the code that creates the user table above. This declares the id column as the primary key.")]),t._v(" "),s("p",[t._v("The primary key is implicitly declared as a structure in the "),s("code",[t._v("PrimaryKeyConstraint")]),t._v(" object. This can be confirmed as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("primary_key\nPrimaryKeyConstraint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("Along with the primary key, foreign keys can also be declared as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" ForeignKey\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_table "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Declaring Foreign Key as `ForeignKey` object.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ForeignKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account.id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'email_address'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("ul",[s("li",[t._v("You can declare a foreign key column in the form of "),s("code",[t._v("ForeignKey('table_name.foreign_key')")]),t._v(".\n"),s("ul",[s("li",[t._v("In this case, you can omit the data type of the "),s("code",[t._v("Column")]),t._v(" object. The data type is automatically inferred by locating the column corresponding to the foreign key.")])])]),t._v(" "),s("li",[t._v("You can also declare a "),s("code",[t._v("NOT NULL")]),t._v(" constraint on a column by passing the "),s("code",[t._v("nullable=False")]),t._v(" parameter and value.")])]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"applying-to-your-database"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#applying-to-your-database"}},[t._v("#")]),t._v(" Applying to your database")]),t._v(" "),s("p",[t._v("We have declared database tables using SQLAlchemy so far. Now, let's make these declared tables actually get created in the database.")]),t._v(" "),s("p",[t._v("Execute "),s("code",[t._v("metadata.create_all()")]),t._v(" as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The above code creates all tables recorded in the metadata instance.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# As a result, it executes the following queries.")]),t._v("\n\nBEGIN "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_account"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nPRAGMA main"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCREATE TABLE user_account "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" INTEGER NOT NULL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n name VARCHAR"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n fullname VARCHAR"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n PRIMARY KEY "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCREATE TABLE address "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" INTEGER NOT NULL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_id INTEGER NOT NULL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n email_address VARCHAR NOT NULL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n PRIMARY KEY "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n FOREIGN KEY"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" REFERENCES user_account "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCOMMIT\n")])])]),s("br"),t._v(" "),s("h2",{attrs:{id:"defining-table-metadata-the-orm-way"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#defining-table-metadata-the-orm-way"}},[t._v("#")]),t._v(" Defining table metadata the ORM way")]),t._v(" "),s("p",[t._v("We will create the same database structure and use the same constraints as above, but this time we will proceed using the ORM approach.")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"setting-the-registry-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#setting-the-registry-object"}},[t._v("#")]),t._v(" Setting the "),s("code",[t._v("registry")]),t._v(" object.")]),t._v(" "),s("p",[t._v("First of all, create a "),s("code",[t._v("registry")]),t._v(" object as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" registry\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" registry"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("The "),s("code",[t._v("registry")]),t._v(" object contains a "),s("code",[t._v("MetaData")]),t._v(" object.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata\nMetaData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("Now we can execute the following code.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mapper_registry"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("generate_base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("blockquote",[s("p",[t._v("The above process can be simplified using "),s("code",[t._v("declarative_base")]),t._v(" as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" declarative_base\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" declarative_base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"declaring-the-orm-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#declaring-the-orm-object"}},[t._v("#")]),t._v(" Declaring the ORM object")]),t._v(" "),s("p",[t._v("By defining a subclass that inherits from the "),s("code",[t._v("Base")]),t._v(" object, you can declare tables in the database using the ORM approach.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" relationship\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("User")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# A name of the table to be used in the database.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" __tablename__ "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" name "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" fullname "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" addresses "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Address"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("__repr__")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-interpolation"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"User(id=')]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v(", name=")]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v(", fullname=")]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),s("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v(')"')])]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" __tablename__ "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'address'")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" email_address "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_id "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ForeignKey"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account.id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"User"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"addresses"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("__repr__")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string-interpolation"}},[s("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"Address(id=')]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v(", email_address=")]),s("span",{pre:!0,attrs:{class:"token interpolation"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),s("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v(')"')])]),t._v("\n")])])]),s("p",[t._v("The "),s("code",[t._v("User")]),t._v(" and "),s("code",[t._v("Address")]),t._v(" objects include a "),s("code",[t._v("Table")]),t._v(" object.")]),t._v(" "),s("p",[t._v("You can check this through the "),s("code",[t._v("__table__")]),t._v(" attribute as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" User"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__table__\nTable"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" MetaData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" schema"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"creating-an-orm-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#creating-an-orm-object"}},[t._v("#")]),t._v(" Creating an ORM object")]),t._v(" "),s("p",[t._v("After defining the table, you can create an ORM object as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" User"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Cheeks"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy\nUser"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"applying-to-your-database-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#applying-to-your-database-2"}},[t._v("#")]),t._v(" Applying to your database")]),t._v(" "),s("p",[t._v("Now, you can apply the tables declared with ORM to the actual database as follows.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("br"),t._v(" "),s("h2",{attrs:{id:"importing-tables-from-an-existing-database-into-an-orm-object"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#importing-tables-from-an-existing-database-into-an-orm-object"}},[t._v("#")]),t._v(" Importing tables from an existing database into an ORM object")]),t._v(" "),s("p",[t._v("Aside from the above methods, there is a way to retrieve tables from the database without declaring them directly.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_table "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" metadata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" autoload_with"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("engine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nBEGIN "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("raw sql"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nSELECT sql FROM "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("SELECT "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" FROM sqlite_master UNION ALL SELECT "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" FROM sqlite_temp_master"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" WHERE name "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ? AND "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'table'")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("raw sql"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some_table'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("foreign_key_list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nPRAGMA main"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("index_list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nROLLBACK\n")])])]),s("p",[t._v("Now it can be used as follows:")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_table\nTable"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some_table'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" MetaData"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'x'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INTEGER"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("some_table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'y'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INTEGER"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("some_table"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n schema"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/15.dca0d300.js b/assets/js/15.dca0d300.js new file mode 100644 index 0000000..ca7a817 --- /dev/null +++ b/assets/js/15.dca0d300.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{415:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"querying-rows-using-core-and-orm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#querying-rows-using-core-and-orm"}},[t._v("#")]),t._v(" Querying Rows Using "),a("code",[t._v("Core")]),t._v(" and "),a("code",[t._v("ORM")])]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("This chapter covers the most frequently used "),a("code",[t._v("Select")]),t._v(" in SQLAlchemy.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"constructing-sql-expressions-with-select"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#constructing-sql-expressions-with-select"}},[t._v("#")]),t._v(" Constructing SQL Expressions with "),a("code",[t._v("select()")])]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("select()")]),t._v(" constructor allows you to create query statements in the same way as the "),a("code",[t._v("insert()")]),t._v(" constructor.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" select\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("p",[t._v("Similarly, you can put a query in the "),a("code",[t._v("Connection.execute()")]),t._v(" method to execute a query statement, just like any SQL constructor at the same level ("),a("code",[t._v("select")]),t._v(", "),a("code",[t._v("insert")]),t._v(", "),a("code",[t._v("update")]),t._v(","),a("code",[t._v("create")]),t._v(" and etc.).")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("On the other hand, if you want to use the ORM to execute a "),a("code",[t._v("select")]),t._v(" query statement, you should use "),a("code",[t._v("Session.exeuct()")]),t._v(".")]),t._v(" "),a("p",[t._v("The result returns a "),a("code",[t._v("Row")]),t._v(" object, just like in the example just now. This object contains the "),a("code",[t._v("User")]),t._v(" object that we defined in the "),a("a",{attrs:{href:"https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/4.%20Working%20with%20Database%20Metadata.html#create-a-table-object-and-add-it-to-your-metadata",target:"_blank",rel:"noopener noreferrer"}},[t._v("previous tutorial"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Print each row in an instance of the User object")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"setting-up-the-from-clause-and-columns"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-up-the-from-clause-and-columns"}},[t._v("#")]),t._v(" Setting up the "),a("code",[t._v("FROM")]),t._v(" clause and columns")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("select()")]),t._v(" function can take a variety of objects as positional arguments, including "),a("code",[t._v("Column")]),t._v(" and "),a("code",[t._v("Table")]),t._v(".")]),t._v(" "),a("p",[t._v("These argument values can be represented as the return value of the "),a("code",[t._v("select()")]),t._v(" function, i.e., as an SQL query statement, and can also set the "),a("code",[t._v("FROM")]),t._v(" clause.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("To retrieve each column using the "),a("code",[t._v("Core")]),t._v(", you can access the "),a("code",[t._v("Column")]),t._v(" object through the "),a("code",[t._v("Table.c")]),t._v(" accessor.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-entity-and-column-lookups"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-entity-and-column-lookups"}},[t._v("#")]),t._v(" ORM entity and column lookups")]),t._v(" "),a("p",[t._v("When implementing SQL queries in SQLAlchemy, you can use ORM entities like the "),a("code",[t._v("User")]),t._v(" object or attributes that map to columns, such as "),a("code",[t._v("User.name")]),t._v(", to represent tables or columns. The example below queries the "),a("code",[t._v("User")]),t._v(" entity, but in fact, the result is the same as when using "),a("code",[t._v("user_table")]),t._v(".")]),t._v(" "),a("p",[t._v("The example below looks up the "),a("code",[t._v("User")]),t._v(" entity, but the results are the same as when using "),a("code",[t._v("user_table")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("In the above example, the query can be executed in the same way using ORM's "),a("code",[t._v("Session.execute()")]),t._v(".")]),t._v(" "),a("p",[t._v("However, there is a difference between querying the "),a("code",[t._v("User")]),t._v(" entity and querying "),a("code",[t._v("user_info")]),t._v(". Whether you query "),a("code",[t._v("user_info")]),t._v(" or the "),a("code",[t._v("User")]),t._v(" entity, in both cases a Row object is returned.")]),t._v(" "),a("p",[t._v("But, when querying the "),a("code",[t._v("User")]),t._v(" entity, the returned "),a("code",[t._v("Row")]),t._v(" object includes a "),a("code",[t._v("User")]),t._v(" instance.")]),t._v(" "),a("blockquote",[a("p",[t._v("Tips:")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("user_table")]),t._v(" and "),a("code",[t._v("User")]),t._v(" were created in the "),a("a",{attrs:{href:"https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/4.%20Working%20with%20Database%20Metadata.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("previous chapter"),a("OutboundLink")],1),t._v(",\nwhere "),a("code",[t._v("user_table")]),t._v(" is a "),a("code",[t._v("Table")]),t._v(" object, and\n"),a("code",[t._v("User")]),t._v(" is an entity that inherits from the "),a("code",[t._v("Base")]),t._v(" object and includes a "),a("code",[t._v("Table")]),t._v(' object."')])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Alternatively, you can query the desired columns using object attributes(class-bound attributes).")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("When querying object attributes using "),a("code",[t._v("Session.execute()")]),t._v(", the values of the object attributes sent as arguments (column values) are returned as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\trow "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("These methods can also be mixed and used together, as shown in the following example")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"querying-labeled-sql-expressions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#querying-labeled-sql-expressions"}},[t._v("#")]),t._v(" Querying Labeled SQL Expressions")]),t._v(" "),a("p",[t._v("When you execute a query like SELECT name AS username FROM user_account, you can get the following results:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[t._v("username")])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("patrick")])]),t._v(" "),a("tr",[a("td",[t._v("sandy")])]),t._v(" "),a("tr",[a("td",[t._v("spongebob")])])])]),t._v(" "),a("p",[t._v("Here, we've labeled the "),a("code",[t._v("name")]),t._v(" column as "),a("code",[t._v("username")]),t._v(", which is why "),a("code",[t._v("username")]),t._v(" appears as the column header. This functionality can be implemented in SQLAlchemy using the "),a("code",[t._v("ColumnElement.label()")]),t._v(" function, as shown below:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cast\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Labeling is done like this.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Username: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"username"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The labeled part can be accessed like this.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("username"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" patrick\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" sandy\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" spongebob\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"querying-string-columns"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#querying-string-columns"}},[t._v("#")]),t._v(" Querying String Columns")]),t._v(" "),a("p",[t._v("Usually, columns are queried using the "),a("code",[t._v("Select")]),t._v(" object or the "),a("code",[t._v("select()")]),t._v(" constructor, but sometimes you need to query a column along with an arbitrary string. This section covers how to query such string data.")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("text()")]),t._v(" constructor was introduced in a "),a("a",{attrs:{href:"https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/3.%20Executing%20Transactions%20and%20Queries.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("previous chapter 3"),a("OutboundLink")],1),t._v(". Transactions and Database API Operations. It allows you to directly use a "),a("code",[t._v("SELECT")]),t._v(" statement within it.")]),t._v(" "),a("p",[t._v("Let's consider a scenario where we want to execute a query like "),a("code",[t._v("SELECT 'some_phrase', name FROM user_account")]),t._v(". In this case, since some_phrase is a string, it must be enclosed in either single or double quotes. Consequently, the output will inevitably have single quotes around the string.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" text\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"'some phrase'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("Therefore, instead of "),a("code",[t._v("text()")]),t._v(", it is common to use "),a("code",[t._v("literal_column()")]),t._v(" to solve the problem of having single quotes attached to the output. "),a("code",[t._v("text()")]),t._v(" and "),a("code",[t._v("literal_column()")]),t._v(" are almost similar, but "),a("code",[t._v("literal_column()")]),t._v(' explicitly signifies a column and can be labeled for use in subqueries and other SQL expressions."')]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" literal_column\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" literal_column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"'some phrase'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(", ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" patrick\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sandy\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" spongebob\n\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"where-clauses"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#where-clauses"}},[t._v("#")]),t._v(" "),a("code",[t._v("WHERE")]),t._v(" Clauses")]),t._v(" "),a("p",[t._v("Using SQLAlchemy, you can easily write queries to output data where conditions like "),a("code",[t._v("name = 'thead'")]),t._v(" or "),a("code",[t._v("user_id > 10")]),t._v(" are met using Python operators.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nuser_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("name_1\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("user_id_1\n")])])]),a("p",[t._v("To create a "),a("code",[t._v("WHERE")]),t._v(" clause, you can pass arguments to the "),a("code",[t._v("Select.where()")]),t._v(" method.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("p",[t._v("When implementing a "),a("code",[t._v("JOIN")]),t._v(" with a "),a("code",[t._v("WHERE")]),t._v(" clause, it can be written as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE user_account.name = :name_1 AND address.user_id = user_account.id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The same expression can be used, but you can also pass parameters to the where() method.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE user_account.name = :name_1 AND address.user_id = user_account.id\n"""')]),t._v("\n")])])]),a("p",[t._v("It's also possible to use conjunctions such as "),a("code",[t._v("and_()")]),t._v(" and "),a("code",[t._v("or_()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" or_\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" or_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE (user_account.name = :name_1 OR user_account.name = :name_2)\nAND address.user_id = user_account.id\n"""')]),t._v("\n")])])]),a("p",[t._v("For simple equality or inequality comparisons, "),a("code",[t._v("Select.filter_by()")]),t._v(" is often used.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("filter_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1 AND user_account.fullname = :fullname_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"specifying-the-from-clause-and-joins"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#specifying-the-from-clause-and-joins"}},[t._v("#")]),t._v(" Specifying the "),a("code",[t._v("FROM")]),t._v(" Clause and "),a("code",[t._v("JOIN")]),t._v("s")]),t._v(" "),a("p",[t._v("As mentioned before, the "),a("code",[t._v("FROM")]),t._v(" clause is automatically set based on the columns included as arguments in the "),a("code",[t._v("select()")]),t._v(" method, without the need for explicit specification.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Even without specifying the FROM clause explicitly, it is set and displayed in the output.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("If you want to reference columns from two different tables in the positional arguments of "),a("code",[t._v("select()")]),t._v(", you can separate them with a comma ("),a("code",[t._v(",")]),t._v(").")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account, address\n"""')]),t._v("\n")])])]),a("p",[t._v("If you want to join two different tables, there are two methods you can use:")]),t._v(" "),a("p",[t._v("One is the "),a("code",[t._v("Select.join()")]),t._v(" method, which allows you to explicitly specify the left and right tables for the "),a("code",[t._v("JOIN")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("The other is to explicitly specify only the right table in the "),a("code",[t._v("Select.join()")]),t._v(" method, and let the other table be implicitly referenced when selecting columns.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# This expression is the same, but the left table to join (user_table) is expressed implicitly.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("Alternatively, if you want to write the two JOINing tables more explicitly, or if you want to provide explicit additional options in the "),a("code",[t._v("FROM")]),t._v(" clause, you can write it as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("Another case for using "),a("code",[t._v("Select.select_from()")]),t._v(" is when we cannot implicitly set the "),a("code",[t._v("FROM")]),t._v(" clause through the columns we want to query.")]),t._v(" "),a("p",[t._v("For example, to query "),a("code",[t._v("count(*)")]),t._v(" in a typical SQL query, you would need to use "),a("code",[t._v("sqlalchemy.sql.expression.func")]),t._v(" from SQLAlchemy.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'*'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(:count_2) AS count_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"setting-the-on-clause"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-the-on-clause"}},[t._v("#")]),t._v(" Setting the "),a("code",[t._v("ON")]),t._v(" Clause")]),t._v(" "),a("p",[t._v("But there was something unusual, wasn't there?\nIn fact, in the previous example, when joining two tables using "),a("code",[t._v("Select.select_from()")]),t._v(" or "),a("code",[t._v("select.join()")]),t._v(", the "),a("code",[t._v("ON")]),t._v(" clause was implicitly set.")]),t._v(" "),a("p",[t._v("This automatic setting of the "),a("code",[t._v("ON")]),t._v(" clause happened because the "),a("code",[t._v("user_table")]),t._v(" and "),a("code",[t._v("address_table")]),t._v(" objects have a ForeignKeyConstraint, i.e., a foreign key constraint, which led to the automatic setting.")]),t._v(" "),a("p",[t._v("If the two tables targeted for a Join lack such constraint keys, you must explicitly specify the "),a("code",[t._v("ON")]),t._v(" clause. This functionality can be explicitly set by passing parameters to the "),a("code",[t._v("Select.join()")]),t._v(" or "),a("code",[t._v("Select.join_from()")]),t._v(" methods for the "),a("code",[t._v("ON")]),t._v(" clause.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"outer-full-join"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#outer-full-join"}},[t._v("#")]),t._v(" OUTER, FULL Join")]),t._v(" "),a("p",[t._v("To implement "),a("code",[t._v("LEFT OUTER JOIN")]),t._v(" or "),a("code",[t._v("FULL OUTER JOIN")]),t._v(" In SQLAlchemy, you can use the keyword arguments "),a("code",[t._v("Select.join.isouter")]),t._v(" and "),a("code",[t._v("Select.join.full")]),t._v(" in the "),a("code",[t._v("Select.join()")]),t._v(" and "),a("code",[t._v("Select.join_from()")]),t._v(" methods.")]),t._v(" "),a("p",[t._v("An examples of implementing the "),a("code",[t._v("LEFT OUTER JOIN")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" isouter"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account LEFT OUTER JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("An examples of implementing the "),a("code",[t._v("FULL OUTER JOIN")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" full"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account FULL OUTER JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"order-by-group-by-having"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#order-by-group-by-having"}},[t._v("#")]),t._v(" ORDER BY, GROUP BY, HAVING")]),t._v(" "),a("ul",[a("li",[t._v("The "),a("code",[t._v("ORDER BY")]),t._v(" clause allows you to set the order of the rows retrieved by the "),a("code",[t._v("SELECT")]),t._v(" clause.")]),t._v(" "),a("li",[t._v("The "),a("code",[t._v("GROUP BY")]),t._v(" clause creates groups based on a specific column for rows aggregated by group functions.")]),t._v(" "),a("li",[a("code",[t._v("HAVING")]),t._v(" applies conditions to groups created by the "),a("code",[t._v("GROUP BY")]),t._v(" clause.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"order-by"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#order-by"}},[t._v("#")]),t._v(" ORDER BY")]),t._v(" "),a("p",[t._v("You can implement the ORDER BY feature using "),a("code",[t._v("Select.order_by()")]),t._v(". This method accepts Column objects or similar objects as positional arguments.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account ORDER BY user_account.name\n"""')]),t._v("\n")])])]),a("p",[t._v("Ascending and descending order can be implemented using the "),a("code",[t._v("ColumnElement.asc()")]),t._v(" and "),a("code",[t._v("ColumnElement.desc()")]),t._v(" modifiers, respectively.")]),t._v(" "),a("p",[t._v("The following example orders by the "),a("code",[t._v("user_account.fullname")]),t._v(" column in descending order.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("desc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account ORDER BY user_account.fullname DESC\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"aggregations-group-by-having"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#aggregations-group-by-having"}},[t._v("#")]),t._v(" Aggregations: GROUP BY, HAVING")]),t._v(" "),a("p",[t._v("In SQL, aggregate functions can also be used to combine multiple rows into a single row. Examples of aggregate functions include "),a("code",[t._v("COUNT()")]),t._v(", "),a("code",[t._v("SUM()")]),t._v(", and "),a("code",[t._v("AVG()")]),t._v(".")]),t._v(" "),a("p",[t._v("SQLAlchemy provides SQL functions using the func namespace, where "),a("code",[t._v("func")]),t._v(" creates a "),a("code",[t._v("Function")]),t._v(" instance when given the name of an SQL function.")]),t._v(" "),a("p",[t._v("In the example below, the "),a("code",[t._v("count()")]),t._v(" function is called to render the "),a("code",[t._v("user_account.id")]),t._v(" column with the SQL "),a("code",[t._v("COUNT()")]),t._v(" function.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" count_fn "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("count_fn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\ncount(user_account.id)\n"""')]),t._v("\n")])])]),a("p",[t._v("More details about SQL functions are explained in "),a("a",{attrs:{href:""}},[t._v("Handling SQL Functions")]),t._v(".")]),t._v(" "),a("p",[t._v("To summarize:")]),t._v(" "),a("p",[a("code",[t._v("GROUP BY")]),t._v(" is a function needed to divide the retrieved rows into specific groups. In SQL, if a few columns are queried in the "),a("code",[t._v("SELECT")]),t._v(" clause, these columns are directly or indirectly dependent on the primary key in the "),a("code",[t._v("GROUP BY")]),t._v(".")]),t._v(" "),a("p",[a("code",[t._v("HAVING")]),t._v(" is necessary to apply conditions to groups created by "),a("code",[t._v("GROUP BY")]),t._v(" (similar to the "),a("code",[t._v("WHERE")]),t._v(" clause because it places conditions on groups).")]),t._v(" "),a("p",[t._v("In SQLAlchemy, "),a("code",[t._v("GROUP BY")]),t._v(" and "),a("code",[t._v("HAVING")]),t._v(" can be implemented using "),a("code",[t._v("Select.group_by()")]),t._v(" and "),a("code",[t._v("Select.having()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" having"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('""" The syntax above represents the SQL statement below.\nSELECT user_account.name, count(address.id) AS count\nFROM user_account JOIN address ON user_account.id = address.user_id GROUP BY user_account.name\nHAVING count(address.id) > ?\n[...] (1,)\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"grouping-or-ordering-by-alias"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#grouping-or-ordering-by-alias"}},[t._v("#")]),t._v(" Grouping or ordering by alias")]),t._v(" "),a("p",[t._v("In some database backends, when using aggregate functions to query tables, it is important not to "),a("strong",[t._v("restate")]),t._v(" already specified aggregate functions in the "),a("code",[t._v("ORDER BY")]),t._v(" or "),a("code",[t._v("GROUP BY")]),t._v(" clauses.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# NOT GOOD")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("COUNT")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("GROUP")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# CORRECT")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("COUNT")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" cnt_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("GROUP")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" cnt_id\n")])])]),a("p",[t._v("Therefore, to implement "),a("code",[t._v("ORDER BY")]),t._v(" or "),a("code",[t._v("GROUP BY")]),t._v(" using aliases, you just need to insert the alias you want to use as an argument in the "),a("code",[t._v("Select.order_by()")]),t._v(" or "),a("code",[t._v("Select.group_by()")]),t._v(" methods.")]),t._v(" "),a("p",[t._v("The alias used here is not rendered first; instead, the alias used in the column clause is rendered first. If the rendered alias does not match anything in the rest of the query, an error occurs.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" desc\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The alias 'num_addresses' is used in both the column and in the order_by clause.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'num_addresses'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\\\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" desc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"num_addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.user_id, count(address.id) AS num_addresses\nFROM address GROUP BY address.user_id ORDER BY address.user_id, num_addresses DESC\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"using-aliases"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-aliases"}},[t._v("#")]),t._v(" Using aliases")]),t._v(" "),a("p",[t._v("When using "),a("code",[t._v("JOIN")]),t._v(" to query multiple tables, it's often necessary to repeatedly write the table names in the query.")]),t._v(" "),a("p",[t._v("In SQL, this issue can be addressed by giving "),a("em",[t._v("aliases")]),t._v(" to table names or subqueries, reducing repetition.")]),t._v(" "),a("p",[t._v("In SQLAlchemy, such aliases can be implemented using the Core's "),a("code",[t._v("FromClause.alias()")]),t._v(" function.")]),t._v(" "),a("p",[t._v("Within the "),a("code",[t._v("Table")]),t._v(" object namespace, there are "),a("code",[t._v("Column")]),t._v(" objects, allowing access to column names via "),a("code",[t._v("Table.c")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("Similarly, in the "),a("code",[t._v("Alias")]),t._v(" object namespace, there are "),a("code",[t._v("Column")]),t._v(" objects, making it possible to access columns via "),a("code",[t._v("Alias.c")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Both user_alias_1 and user_alias_2 are Alias objects.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("‘table1’"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("‘table2’"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# To access columns using the newly created table aliases,")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# you should use Alias.c.column_name")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT table1.name, table2.name AS name_1 \nFROM user_account AS table1 JOIN user_account AS table2 ON table1.id > table2.id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-entity-aliases"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-entity-aliases"}},[t._v("#")]),t._v(" ORM Entity Aliases")]),t._v(" "),a("p",[t._v("The ORM in SQLAlchemy also has a function similar to the "),a("code",[t._v("FromClause.alias()")]),t._v(" method, known as "),a("code",[t._v("aliased()")])]),t._v(" "),a("p",[t._v("This ORM "),a("code",[t._v("aliased()")]),t._v(" function internally creates an "),a("code",[t._v("Alias")]),t._v(" object for the originally mapped "),a("code",[t._v("Table")]),t._v(" object, while maintaining ORM functionalities.")]),t._v(" "),a("blockquote",[a("p",[t._v("Tips:")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("user_table")]),t._v(" and "),a("code",[t._v("User")]),t._v(" were created in the "),a("a",{attrs:{href:"https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/4.%20Working%20with%20Database%20Metadata.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("previous chapter"),a("OutboundLink")],1),t._v(",\nwhere "),a("code",[t._v("user_table")]),t._v(" is a "),a("code",[t._v("Table")]),t._v(" object, and\n"),a("code",[t._v("User")]),t._v(" is an entity that inherits from the "),a("code",[t._v("Base")]),t._v(" object and includes a "),a("code",[t._v("Table")]),t._v(' object."')])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# In the examples, it is applied to the User or Address entities.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname \nFROM user_account JOIN address AS address_1 ON user_account.id = address_1.user_id JOIN address AS address_2 ON user\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"subqueries-and-cte-common-table-expression-s"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#subqueries-and-cte-common-table-expression-s"}},[t._v("#")]),t._v(" Subqueries and CTE(Common Table Expression)s")]),t._v(" "),a("p",[t._v("This section explains subqueries typically found in the "),a("code",[t._v("FROM")]),t._v(" clause of a "),a("code",[t._v("SELECT")]),t._v(" statement. It also covers CTEs (Common Table Expressions), which are used in a similar way to subqueries but with additional functionalities.")]),t._v(" "),a("blockquote",[a("p",[t._v("More about CTE")]),t._v(" "),a("p",[t._v("A CTE is a temporary result set within a query that can be referenced multiple times within the same query.\nYou can check the official links to describe CTEs in RDBMS below.")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://www.postgresql.org/docs/current/queries-with.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("PostgreSQL: WITH Queries (Common Table Expressions)"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://dev.mysql.com/doc/refman/8.0/en/with.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("MySQL: WITH (Common Table Expressions)"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://mariadb.com/kb/en/with/",target:"_blank",rel:"noopener noreferrer"}},[t._v("MariaDB: WITH"),a("OutboundLink")],1)])])]),t._v(" "),a("p",[t._v("SQLAlchemy represents subqueries using the "),a("code",[t._v("Subquery")]),t._v(" object created by "),a("code",[t._v("Select.subquery()")]),t._v(", and CTEs are represented using "),a("code",[t._v("Select.cte()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(address.id) AS count, address.user_id\nFROM address GROUP BY address.user_id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The ON clause automatically binds two tables")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# that are already constrained by a foreign key.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname, anon_1.count\nFROM user_account JOIN (SELECT count(address.id) AS count, address.user_id AS user_id\nFROM address GROUP BY address.user_id) AS anon_1 ON user_account.id = anon_1.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"hierarchy-query"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#hierarchy-query"}},[t._v("#")]),t._v(" Hierarchy Query")]),t._v(" "),a("p",[t._v("The method of using CTE syntax in SQLAlchemy is almost identical to how subquery syntax is used. Instead of calling the "),a("code",[t._v("Select.subquery()")]),t._v(" method, you use "),a("code",[t._v("Select.cte()")]),t._v(", allowing the resulting object to be used as a FROM element.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nWITH anon_1 AS\n(SELECT count(address.id) AS count, address.user_id AS user_id\nFROM address GROUP BY address.user_id)\n SELECT user_account.name, user_account.fullname, anon_1.count\nFROM user_account JOIN anon_1 ON user_account.id = anon_1.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-entity-subqueries-cte"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-entity-subqueries-cte"}},[t._v("#")]),t._v(" ORM Entity Subqueries, CTE")]),t._v(" "),a("p",[t._v("You can see that "),a("code",[t._v("aliased()")]),t._v(" performs the same operation for "),a("code",[t._v("Subquery")]),t._v(" and "),a("code",[t._v("CTE")]),t._v(" subqueries.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("like"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'%@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('""" The above syntax represents the following query:\n\nSELECT user_account.id, user_account.name, user_account.fullname,\nanon_1.id AS id_1, anon_1.email_address, anon_1.user_id\nFROM user_account JOIN\n(SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id\nFROM address\nWHERE address.email_address NOT LIKE ?) AS anon_1 ON user_account.id = anon_1.user_id\nORDER BY user_account.id, anon_1.id\n[...] (\'%@aol.com\',)\n"""')]),t._v("\n\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Below is an example of querying the same result using the CTE constructor:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" cte "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("like"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'%@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_cte "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"scalar-subqueries-and-correlated-queries"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#scalar-subqueries-and-correlated-queries"}},[t._v("#")]),t._v(" Scalar Subqueries and Correlated Queries")]),t._v(" "),a("p",[t._v("Before explaining scalar subqueries, let's briefly discuss subqueries in SQL. "),a("a",{attrs:{href:"https://rinuas.tistory.com/entry/%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%ACSub-Query",target:"_blank",rel:"noopener noreferrer"}},[t._v("출처:바이헨 블로그"),a("OutboundLink")],1)]),t._v(" "),a("p",[t._v('A "'),a("em",[t._v("subquery")]),t._v('" is a '),a("code",[t._v("SELECT")]),t._v(' statement within another SQL statement, and the outer SQL statement is referred to as the "'),a("em",[t._v("main query")]),t._v('".')]),t._v(" "),a("p",[t._v("The types of subqueries are determined based on whether they reference columns of the main query, where they are declared, and the number of rows they return.")]),t._v(" "),a("ul",[a("li",[t._v("Classification based on reference to main query columns:\n"),a("ul",[a("li",[a("strong",[t._v("Correlated Subqueries")]),t._v(": The subquery references columns of the main query.")]),t._v(" "),a("li",[a("strong",[t._v("Non-correlated Subqueries")]),t._v(": The subquery does not reference the main query's columns and operates independently, used to convey information to the main query.")])])]),t._v(" "),a("li",[t._v("Classification based on declaration position:\n"),a("ul",[a("li",[a("strong",[t._v("Scalar Subqueries")]),t._v(": Subqueries that appear in the column position of a SELECT statement (correlated).")]),t._v(" "),a("li",[a("strong",[t._v("Inline Views")]),t._v(": Subqueries in the FROM clause (correlated).")]),t._v(" "),a("li",[a("strong",[t._v("Nested Subqueries")]),t._v(": Subqueries in the WHERE clause (non-correlated).")])])]),t._v(" "),a("li",[t._v("Classification based on the number of rows returned:\n"),a("ul",[a("li",[a("strong",[t._v("Single-row Subqueries")]),t._v(" (return one row)")]),t._v(" "),a("li",[a("strong",[t._v("Multi-row Subqueries")]),t._v(" (return more than one row): Used with IN, ANY, ALL, EXISTS.")])])])]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("In SQLAlchemy, scalar subqueries use "),a("code",[t._v("ScalarSelect")]),t._v(", which is part of the "),a("code",[t._v("ColumnElement")]),t._v(" object, while general subqueries use "),a("code",[t._v("Subquery")]),t._v(", which is in the "),a("code",[t._v("FromClause")]),t._v(" object.")]),t._v(" "),a("p",[t._v("Scalar subqueries are often used as described earlier in "),a("a",{attrs:{href:"#aggregations-group-by-having"}},[t._v("Aggregations")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Implementing Scalar subquery using Select.scalar_subquery()")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" scalar_subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# ... is equal to "ScalarSelect" type')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\n(SELECT count(address.id) AS count_1\nFROM address, user_account\nWHERE user_account.id = address.user_id)\n"""')]),t._v("\n")])])]),a("p",[t._v("Scalar subqueries implemented using "),a("code",[t._v("Select.scalar_subquery()")]),t._v(" render the "),a("code",[t._v("user_account")]),t._v(" and "),a("code",[t._v("address")]),t._v(" in the FROM clause, but since the "),a("code",[t._v("user_account")]),t._v(" table is already present in the main query, it is not rendered again in the scalar subquery.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address_count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, (SELECT count(address.id) AS count_1\nFROM address\nWHERE user_account.id = address.user_id) AS address_count\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("Meanwhile, when writing correlated queries, the connections between tables can become ambiguous.")]),t._v(" "),a("blockquote",[a("p",[t._v("I did not understand the correlated query example in the tutorial.\nIf someone understands it well, please contribute to this document.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"union-union-all-operators"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#union-union-all-operators"}},[t._v("#")]),t._v(" UNION, UNION ALL operators")]),t._v(" "),a("p",[t._v("In SQL, terms like "),a("code",[t._v("UNION")]),t._v(" and "),a("code",[t._v("UNION ALL")]),t._v(" are used to combine two "),a("code",[t._v("SELECT")]),t._v(" statements.\nQueries can be executed as shown below.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("union")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n")])])]),a("p",[t._v("Additionally, SQL supports set operations like "),a("code",[t._v("INTERSECT")]),t._v(" (intersection) and "),a("code",[t._v("EXCEPT")]),t._v(" (difference).\nIn SQLAlchemy, for Select objects, functions such as "),a("code",[t._v("union()")]),t._v(", "),a("code",[t._v("intersect()")]),t._v(", "),a("code",[t._v("except_()")]),t._v(", "),a("code",[t._v("union_all()")]),t._v(", "),a("code",[t._v("intersect_all()")]),t._v(", and "),a("code",[t._v("except_all()")]),t._v(" are available.")]),t._v(" "),a("p",[t._v("The return value of these functions is a "),a("code",[t._v("CompoundSelect")]),t._v(", which is an object that can be used similarly to "),a("code",[t._v("Select")]),t._v(" but has fewer methods.\nThe "),a("code",[t._v("CompoundSelect")]),t._v(" object returned by "),a("code",[t._v("union_all()")]),t._v(" can be executed with "),a("code",[t._v("Connection.execute()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" union_all\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" union_all"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stmt2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# A value u is a CompoundSelect type.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("Just as "),a("code",[t._v("Select")]),t._v(" provides the "),a("code",[t._v("SelectBase.subquery()")]),t._v(" method to create "),a("code",[t._v("Subquery")]),t._v(" objects, "),a("code",[t._v("CompoundSelect")]),t._v(" objects can similarly be used as subqueries.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"exists-subqueries"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exists-subqueries"}},[t._v("#")]),t._v(" EXISTS Subqueries")]),t._v(" "),a("p",[t._v("SQLAlchemy creates an "),a("code",[t._v("Exists")]),t._v(" object through the "),a("code",[t._v("SelectBase.exists()")]),t._v(" method to implement the "),a("code",[t._v("EXISTS")]),t._v(" clause.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# subq is a Exists type")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" having"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exists"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nEXISTS (SELECT count(address.id) AS count_1 \nFROM address, user_account \nWHERE user_account.id = address.user_id GROUP BY address.user_id \nHAVING count(address.id) > :count_2)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("The "),a("code",[t._v("EXISTS")]),t._v(" clause is more often used in a non-negated form by the way.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# This is a query to select usernames that do not have an email address.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Take a look at the part where the '~' operator is used.\"")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exists"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id \nFROM user_account \nWHERE NOT (EXISTS (SELECT count(address.id) AS count_1 \nFROM address \nWHERE user_account.id = address.user_id GROUP BY address.user_id \nHAVING count(address.id) > :count_2))\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"dealing-with-sql-functions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#dealing-with-sql-functions"}},[t._v("#")]),t._v(" Dealing with SQL functions.")]),t._v(" "),a("p",[t._v("In the earlier section "),a("a",{attrs:{href:"#aggregations-group-by-having"}},[t._v("Aggregations: GROUP BY, HAVING")]),t._v(", the "),a("code",[t._v("func")]),t._v(" object, which acts as a factory for creating new "),a("code",[t._v("Function")]),t._v(" objects, was introduced. When using syntax like "),a("code",[t._v("select()")]),t._v(", you can pass SQL functions created by the "),a("code",[t._v("func")]),t._v(" object as arguments.")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("count()")]),t._v(" : Aggregate functions are used to print the number of rows."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# cnt is a type of .")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" cnt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("cnt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(*) AS count_1FROM user_account\n"""')]),t._v("\n")])])])]),t._v(" "),a("li",[a("code",[t._v("lower()")]),t._v(" : String functions are used to convert strings to lowercase."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("lower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"A String With Much UPPERCASE"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT lower(:lower_2) AS lower_1\n"""')]),t._v("\n")])])])]),t._v(" "),a("li",[a("code",[t._v("now()")]),t._v(" : There is also a function that returns the current time and date. This function is commonly used, so SQLAlchemy helps in easily rendering it across different backends."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("datetime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("datetime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])]),t._v(" "),a("p",[t._v("Different database backends have SQL functions with different names. Therefore, "),a("code",[t._v("func")]),t._v(" allows access to any name in its namespace, automatically interpreting that name as an SQL function and rendering it.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# A data type of crazy_function is Function.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" crazy_function "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("some_crazy_function"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("17")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("crazy_function"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT some_crazy_function(user_account.name, :some_crazy_function_2) AS some_crazy_function_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("Meanwhile, SQLAlchemy provides appropriate data types for commonly used SQL functions like "),a("code",[t._v("count")]),t._v(", "),a("code",[t._v("now")]),t._v(", "),a("code",[t._v("max")]),t._v(", "),a("code",[t._v("concat")]),t._v(", etc., specific to each backend.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" postgresql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("postgresql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT now() AS now_1\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" oracle\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("oracle"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT CURRENT_TIMESTAMP AS now_1 FROM DUAL\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"functions-have-return-types"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#functions-have-return-types"}},[t._v("#")]),t._v(" Functions Have Return Types")]),t._v(" "),a("blockquote",[a("p",[t._v("I did not understand the part about 'Functions Have Return Types' in the original text.\nIf anyone understands this, please contribute to this section. Thank you.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"built-in-functions-have-pre-configured-return-types"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#built-in-functions-have-pre-configured-return-types"}},[t._v("#")]),t._v(" Built-in Functions Have Pre-Configured Return Types")]),t._v(" "),a("blockquote",[a("p",[t._v("I did not understand the part about 'Built-in Functions Have Pre-Configured Return Types' in the original text.\nIf anyone understands this, please contribute to this section. Thank you.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"window-functions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#window-functions"}},[t._v("#")]),t._v(" WINDOW Functions")]),t._v(" "),a("p",[t._v("Window functions are similar to "),a("code",[t._v("GROUP BY")]),t._v(", created to easily define relationships between rows.")]),t._v(" "),a("p",[t._v("In SQLAlchemy, among all SQL functions created by the "),a("code",[t._v("func")]),t._v(" namespace, there is the "),a("code",[t._v("FunctionElement.over()")]),t._v(" method, which implements the "),a("code",[t._v("OVER")]),t._v(" clause.")]),t._v(" "),a("p",[t._v("One of the window functions is "),a("code",[t._v("row_number()")]),t._v(", which counts the number of rows. You can group each row by username and then number the email addresses within each group.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The FunctionElement.over.partition_by parameter is used")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# to render the PARTITION BY clause in the OVER clause.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("row_number"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("over"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("partition_by"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[a("code",[t._v("FunctionElement.over.order_by")]),t._v(" can be used to apply an "),a("code",[t._v("ORDER BY")]),t._v(" clause.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("over"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"special-modifiers-like-within-group-filter"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#special-modifiers-like-within-group-filter"}},[t._v("#")]),t._v(" Special Modifiers like WITHIN GROUP, FILTER")]),t._v(" "),a("p",[t._v("The SQL clause "),a("code",[t._v("WITHIN GROUP")]),t._v(" is used with ordered sets or hypothetical sets along with aggregate functions.")]),t._v(" "),a("p",[t._v("Common ordered set functions include "),a("code",[t._v("percentile_cont()")]),t._v(" and "),a("code",[t._v("rank()")]),t._v(".")]),t._v(" "),a("p",[t._v("In SQLAlchemy, functions such as "),a("code",[t._v("rank")]),t._v(", "),a("code",[t._v("dense_rank")]),t._v(", "),a("code",[t._v("percentile_count")]),t._v(", and "),a("code",[t._v("percentile_disc")]),t._v(" are implemented, each with the "),a("code",[t._v("FunctionElement")]),t._v("."),a("code",[t._v("within_group()")]),t._v(" method.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("unnest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("percentile_disc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.25")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.75")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("within_group"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nunnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))\n"""')]),t._v("\n")])])]),a("p",[t._v('Some backends support the "FILTER" modifier, which can be utilized through the '),a("code",[t._v("FunctionElement.filter()")]),t._v(" method in SQLAlchemy.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("filter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("filter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,\ncount(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"table-valued-functions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#table-valued-functions"}},[t._v("#")]),t._v(" Table-Valued Functions")]),t._v(" "),a("blockquote",[a("p",[t._v("I did not understand the part about 'Table-Valued Functions' in the original text.\nIf anyone understands this, please contribute to this section. Thank you.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"column-value-functions-or-scalar-column-table-valued-functions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#column-value-functions-or-scalar-column-table-valued-functions"}},[t._v("#")]),t._v(" Column Value Functions or Scalar Column (Table Valued Functions)")]),t._v(" "),a("p",[t._v("One of the special syntaxes supported by Oracle and PostgreSQL is functions set in the FROM clause. Examples in PostgreSQL include "),a("code",[t._v("json_array_elements()")]),t._v(", "),a("code",[t._v("json_object_keys()")]),t._v(", "),a("code",[t._v("json_each_text()")]),t._v(", and "),a("code",[t._v("json_each()")]),t._v(".")]),t._v(" "),a("p",[t._v("SQLAlchemy refers to these functions as column values and applies them using the "),a("code",[t._v("FunctionElement.column_valued()")]),t._v(" specifier on a "),a("code",[t._v("Function")]),t._v(" object.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("json_array_elements"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('\'["one", "two"]\'')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("column_valued"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT x\nFROM json_array_elements(:json_array_elements_1) AS x\n"""')]),t._v("\n")])])]),a("p",[t._v("Column value functions can also be used in Oracle as custom SQL functions, as shown below.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" oracle\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalar_strings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("column_valued"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("oracle"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT COLUMN_VALUE s\nFROM TABLE (scalar_strings(:scalar_strings_1)) s\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/16.69771a0f.js b/assets/js/16.69771a0f.js new file mode 100644 index 0000000..70b93e3 --- /dev/null +++ b/assets/js/16.69771a0f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{412:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"inserting-rows-using-core"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#inserting-rows-using-core"}},[t._v("#")]),t._v(" Inserting Rows Using Core")]),t._v(" "),a("p",[t._v("In this chapter, we learn how to INSERT data using the SQLAlchemy Core approach.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"constructing-sql-expressions-with-insert"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#constructing-sql-expressions-with-insert"}},[t._v("#")]),t._v(" Constructing SQL Expressions with "),a("code",[t._v("insert()")])]),t._v(" "),a("p",[t._v("First, you can create an INSERT statement like this:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" insert\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# stmt is an instance of the Insert object.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Spongebob Squarepants"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)'")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("Here, user_table is the Table object we created in the previous chapter. We created it as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" MetaData\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String\n\nmetadata "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nuser_table "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),a("p",[t._v("Looking at "),a("code",[t._v("stmt")]),t._v(", you'll notice that the parameters have not yet been mapped.\nThis can be checked after "),a("code",[t._v("compile()")]),t._v(" it, as shown next.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" compiled "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("compiled"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"executing-the-statement"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#executing-the-statement"}},[t._v("#")]),t._v(" Executing the Statement")]),t._v(" "),a("p",[t._v("Now, let's execute the INSERT statement we created above using the Core approach.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The above code executes the following query.")]),t._v("\n\nBEGIN "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nINSERT INTO user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" VALUES "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nCOMMIT\n")])])]),a("p",[t._v("What information does the result contain, which is obtained from the return value of "),a("code",[t._v("conn.execute(stmt)")]),t._v("?\nresult is a "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.CursorResult",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("CursorResult")]),a("OutboundLink")],1),t._v(" object.\nIt holds various information about the execution results, particularly the "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.Row",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Row")]),a("OutboundLink")],1),t._v(" objects that contain data rows.")]),t._v(" "),a("p",[t._v("Since we have just inserted data, we can check the primary key value of the inserted data as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inserted_primary_key "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# This is also a Row object.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# As the primary key can be composed of multiple columns, it is represented as a tuple.")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"passing-insert-parameters-to-connection-execute"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#passing-insert-parameters-to-connection-execute"}},[t._v("#")]),t._v(" Passing INSERT Parameters to "),a("code",[t._v("Connection.execute()")])]),t._v(" "),a("p",[t._v("Above, we created a statement that included "),a("code",[t._v("values")]),t._v(" along with "),a("code",[t._v("insert")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Spongebob Squarepants"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("However, besides this method, you can also execute an INSERT statement by passing parameters to the "),a("code",[t._v("Connection.execute()")]),t._v(" method. The official documentation suggests this as a more common approach.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"fullname"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Cheeks"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"patrick"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"fullname"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Patrick Star"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The official documentation also explains how to execute statements including subqueries in a separate section. However, it has been deemed not entirely suitable for the tutorial content and is not included in this text.\nFor those interested in this topic, please refer to the "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/tutorial/data_insert.html#insert-usually-generates-the-values-clause-automatically",target:"_blank",rel:"noopener noreferrer"}},[t._v("original documentation"),a("OutboundLink")],1),t._v(".")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"insert-from-select"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#insert-from-select"}},[t._v("#")]),t._v(" "),a("code",[t._v("Insert.from_select()")])]),t._v(" "),a("p",[t._v("Sometimes you need a query to INSERT rows that are received from a SELECT statement, as in the following example.")]),t._v(" "),a("p",[t._v("Such cases can be written as shown in the following code.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" select_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"@aol.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" insert_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("from_select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"email_address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" select_stmt\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("insert_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nINSERT INTO address (user_id, email_address)\nSELECT user_account.id, user_account.name || :name_1 AS anon_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"insert-returning"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#insert-returning"}},[t._v("#")]),t._v(" "),a("code",[t._v("Insert.returning()")])]),t._v(" "),a("p",[t._v("There are situations where you need to receive the value of the processed rows from the database after query processing. This is known as the RETURNING syntax.\nFor an introduction to this, it would be good to read "),a("a",{attrs:{href:"https://wiki.postgresql.org/wiki/UPSERT",target:"_blank",rel:"noopener noreferrer"}},[t._v("this wiki"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("p",[t._v("In SQLAlchemy Core, this "),a("code",[t._v("RETURNING")]),t._v(" syntax can be written as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" insert_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("insert_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nINSERT INTO address (id, user_id, email_address)\nVALUES (:id, :user_id, :email_address)\nRETURNING address.id, address.email_address\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/17.66ba2d35.js b/assets/js/17.66ba2d35.js new file mode 100644 index 0000000..c26e4c5 --- /dev/null +++ b/assets/js/17.66ba2d35.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{411:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"modifying-and-deleting-rows-using-core"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#modifying-and-deleting-rows-using-core"}},[t._v("#")]),t._v(" Modifying and Deleting Rows Using Core")]),t._v(" "),a("p",[t._v("In this chapter, we explain the Update and Delete statements used for modifying and deleting existing rows using the Core approach in SQLAlchemy.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"constructing-sql-expressions-with-update"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#constructing-sql-expressions-with-update"}},[t._v("#")]),t._v(" Constructing SQL Expressions with "),a("code",[t._v("update()")])]),t._v(" "),a("p",[t._v("You can write an UPDATE statement as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" update\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Patrick the Star'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1'")]),t._v("\n")])])]),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Username: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'UPDATE user_account SET fullname=(:name_1 || user_account.name)'")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The original text discusses "),a("code",[t._v("bindparam()")]),t._v(", but since I haven't seen many use cases for it, it is omitted in this text. If you're curious, please refer to "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/tutorial/data_update.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("the original content"),a("OutboundLink")],1),t._v(".")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"correlated-update"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#correlated-update"}},[t._v("#")]),t._v(" Correlated Update")]),t._v(" "),a("p",[t._v("Using a "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/tutorial/data_select.html#tutorial-scalar-subquery",target:"_blank",rel:"noopener noreferrer"}},[t._v("Correlated Subquery"),a("OutboundLink")],1),t._v(", you can utilize rows from another table as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" scalar_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" limit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" scalar_subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("scalar_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=(SELECT address.email_address\nFROM address\nWHERE address.user_id = user_account.id ORDER BY address.id\nLIMIT :param_1)\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"updating-with-conditions-related-to-another-table"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-with-conditions-related-to-another-table"}},[t._v("#")]),t._v(" Updating with Conditions Related to Another Table")]),t._v(" "),a("p",[t._v("When updating a table, there are times when you need to set conditions in relation to information from another table.\nIn such cases, you can use it as shown in the example below.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pat'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=:fullname FROM address\nWHERE user_account.id = address.user_id AND address.email_address = :email_address_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"updating-multiple-tables-simultaneously"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-multiple-tables-simultaneously"}},[t._v("#")]),t._v(" Updating Multiple Tables Simultaneously")]),t._v(" "),a("p",[t._v("You can simultaneously update specific values in multiple tables that meet certain conditions, as shown in the following example.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Pat"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pat@aol.com"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mysql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("mysql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account, address\nSET address.email_address=%s, user_account.fullname=%s\nWHERE user_account.id = address.user_id AND address.email_address = %s\n"""')]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("I did not include a summary of the '"),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/tutorial/data_update.html#parameter-ordered-updates",target:"_blank",rel:"noopener noreferrer"}},[t._v("Parameter Ordered Updates"),a("OutboundLink")],1),t._v("' section from the original text because I did not understand it.\nIf someone understands this part well, it would be appreciated if you could contribute to this document.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"constructing-sql-expressions-with-delete"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#constructing-sql-expressions-with-delete"}},[t._v("#")]),t._v(" Constructing SQL Expressions with "),a("code",[t._v("delete()")])]),t._v(" "),a("p",[t._v("You can write a DELETE statement as follows.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" delete\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account WHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"deleting-with-a-join-to-another-table"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#deleting-with-a-join-to-another-table"}},[t._v("#")]),t._v(" Deleting with a JOIN to Another Table")]),t._v(" "),a("p",[t._v("There are cases where you need to delete data that meets specific conditions after joining with another table. (If this is unclear, refer to "),a("a",{attrs:{href:"https://stackoverflow.com/questions/11366006/mysql-join-on-vs-using",target:"_blank",rel:"noopener noreferrer"}},[t._v("this article"),a("OutboundLink")],1),t._v(" for clarification.)\nIn such cases, you can use it as shown in the example below.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" delete_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mysql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("delete_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("mysql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account USING user_account, address\nWHERE user_account.id = address.user_id AND address.email_address = %s\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"getting-the-number-of-rows-affected-in-update-delete"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#getting-the-number-of-rows-affected-in-update-delete"}},[t._v("#")]),t._v(" Getting the Number of Rows Affected in UPDATE, DELETE")]),t._v(" "),a("p",[t._v("You can obtain the number of rows processed by a query using the "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.CursorResult.rowcount",target:"_blank",rel:"noopener noreferrer"}},[t._v("'Result.rowcount'"),a("OutboundLink")],1),t._v(" property, as shown next.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("begin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Patrick McStar"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rowcount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can use the rowcount property of the Result object.")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The number of rows processed by the query (the same as the number of rows matching the conditions).")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"using-returning-with-update-delete"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-returning-with-update-delete"}},[t._v("#")]),t._v(" Using RETURNING with UPDATE, DELETE")]),t._v(" "),a("p",[t._v("You can use the RETURNING syntax as follows.")]),t._v(" "),a("p",[t._v("For more on the RETURNING syntax, please see "),a("a",{attrs:{href:"https://www.postgresql.org/docs/current/dml-returning.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("this article"),a("OutboundLink")],1),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Patrick the Star'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=:fullname\nWHERE user_account.name = :name_1\nRETURNING user_account.id, user_account.name\n"""')]),t._v("\n")])])]),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" delete_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("delete_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account\nWHERE user_account.name = :name_1\nRETURNING user_account.id, user_account.name\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/18.760e3a59.js b/assets/js/18.760e3a59.js new file mode 100644 index 0000000..bd531d0 --- /dev/null +++ b/assets/js/18.760e3a59.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{413:function(t,s,a){"use strict";a.r(s);var e=a(56),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"manipulating-data-using-orm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#manipulating-data-using-orm"}},[t._v("#")]),t._v(" Manipulating Data Using ORM")]),t._v(" "),a("p",[t._v("Until the previous chapter, we focused on utilizing queries from the "),a("code",[t._v("CORE")]),t._v(" perspective.")]),t._v(" "),a("p",[t._v("In this chapter, we explain the components, lifecycle, and interaction methods of the "),a("code",[t._v("Session")]),t._v(" used in the ORM approach.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"inserting-rows-with-orm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#inserting-rows-with-orm"}},[t._v("#")]),t._v(" Inserting rows with ORM")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("Session")]),t._v(" object, when using ORM, creates Insert objects and emits them in transactions. "),a("code",[t._v("Session")]),t._v(" adds object entries to perform these processes. Then, through a process called "),a("code",[t._v("flush")]),t._v(", it records the new items in the database.")]),t._v(" "),a("h3",{attrs:{id:"instances-of-objects-representing-rows"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#instances-of-objects-representing-rows"}},[t._v("#")]),t._v(" Instances of Objects Representing Rows")]),t._v(" "),a("p",[t._v("In the previous process, we executed INSERT using a Python Dictionary.")]),t._v(" "),a("p",[t._v("In ORM, we directly use user-defined Python objects defined in the table metadata definition.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"squidward"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Squidward Tentacles"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" krabs "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ehkrabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Eugene H. Krabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("We create two "),a("code",[t._v("User")]),t._v(" objects that represent potential database rows to be INSERTed. Because of "),a("code",[t._v("__init__()")]),t._v(" constructor automatically created by ORM mapping, we can create each object using the constructor's column names as keys.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Similar to Core's "),a("code",[t._v("Insert")]),t._v(", ORM integrates it even without including a primary key. The "),a("code",[t._v("None")]),t._v(" value for "),a("code",[t._v("id")]),t._v(" is provided by SQLAlchemy to indicate that the attribute does not have a value yet.")]),t._v(" "),a("p",[t._v("Currently, the two objects ("),a("code",[t._v("squiward")]),t._v(" and "),a("code",[t._v("krabs")]),t._v(") are in a state called "),a("code",[t._v("transient")]),t._v(". The "),a("code",[t._v("transient")]),t._v(" state means they are not yet connected to any database and not yet associated with a "),a("code",[t._v("Session")]),t._v(" object that can generate an "),a("code",[t._v("INSERT")]),t._v(" statement.")]),t._v(" "),a("h3",{attrs:{id:"adding-objects-to-the-session"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-objects-to-the-session"}},[t._v("#")]),t._v(" Adding Objects to the "),a("code",[t._v("Session")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# It is essential to close after use.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Insert an object into session via Session.add() method.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("krabs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("When an object is added to the "),a("code",[t._v("Session")]),t._v(" through "),a("code",[t._v("Session.add()")]),t._v(", it is called being in the "),a("code",[t._v("pending")]),t._v(" state.\nThe pending state means the object has not yet been added to the database.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("new "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can check the objects in the pending state through session.new. Objects are added to the Session using the Session.add() method.")]),t._v("\nIdentitySet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'ehkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Eugene H. Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("ul",[a("li",[a("code",[t._v("IdentitySet")]),t._v(" is a Python set that hashes object IDs in all cases.")]),t._v(" "),a("li",[t._v("That is, it uses the "),a("code",[t._v("id()")]),t._v(" method, not the "),a("code",[t._v("hash()")]),t._v(" function of Python's built-in functions.\"")])]),t._v(" "),a("h3",{attrs:{id:"flushing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#flushing"}},[t._v("#")]),t._v(" Flushing")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("Session")]),t._v(" object uses the "),a("a",{attrs:{href:"https://martinfowler.com/eaaCatalog/unitOfWork.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("unit of work pattern"),a("OutboundLink")],1),t._v(". This means that it accumulates changes but does not actually communicate with the database until necessary.\nThis behavior allows objects in the previously mentioned "),a("code",[t._v("pending")]),t._v(" state to be used more efficiently in SQL DML.\nThe process of actually sending the current changes to the Database via SQL is called flushing.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("flush"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v("\"\"\"\nINSERT INTO user_account (name, fullname) VALUES (?, ?)\n[...] ('squidward', 'Squidward Tentacles')\nINSERT INTO user_account (name, fullname) VALUES (?, ?)\n[...] ('ehkrabs', 'Eugene H. Krabs')\n\"\"\"")]),t._v("\n")])])]),a("p",[t._v("Now, the transaction remains open until one of "),a("code",[t._v("Session.commit()")]),t._v(", "),a("code",[t._v("Session.rollback()")]),t._v(", or "),a("code",[t._v("Session.close()")]),t._v(" is invoked.")]),t._v(" "),a("p",[t._v("While you can use "),a("code",[t._v("Session.flush()")]),t._v(" directly to push the current pending contents, "),a("code",[t._v("Session")]),t._v(" typically features "),a("code",[t._v("autoflush")]),t._v(", so this is usually not necessary. "),a("code",[t._v("Session.commit()")]),t._v(" flushes changes every time it is called.")]),t._v(" "),a("h3",{attrs:{id:"automatically-generated-primary-key-properties"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#automatically-generated-primary-key-properties"}},[t._v("#")]),t._v(" Automatically Generated Primary Key Properties")]),t._v(" "),a("p",[t._v("When a row is inserted, the Python object we created becomes "),a("code",[t._v("persistent")]),t._v(".\nThe "),a("code",[t._v("persistent")]),t._v(" state is associated with the loaded "),a("code",[t._v("Session")]),t._v(" object.")]),t._v(" "),a("p",[t._v("During "),a("code",[t._v("INSERT")]),t._v(", the ORM retrieves the primary key identifier for each new object.\nThis uses the same "),a("code",[t._v("CursorResult.inserted_primary_key")]),t._v(" accessor introduced earlier.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" krabs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("When ORM is flushed, instead of "),a("code",[t._v("executemany")]),t._v(", two separate INSERT statements are used because of this "),a("code",[t._v("CursorResult.inserted_primary_key")]),t._v(".\nIn SQLite, for instance, you need to "),a("code",[t._v("INSERT")]),t._v(" one column at a time to use the auto-increment feature (other various databases like PostgreSQL's IDENTITY or SERIAL function similarly).\nIf a database connection like "),a("code",[t._v("psycopg2")]),t._v(", which can provide primary key information for many rows at once, is used, the ORM optimizes this to "),a("code",[t._v("INSERT")]),t._v(' many rows at once."')])]),t._v(" "),a("h3",{attrs:{id:"identity-map"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#identity-map"}},[t._v("#")]),t._v(" Identity Map")]),t._v(" "),a("p",[a("code",[t._v("Identity Map")]),t._v(" ("),a("code",[t._v("ID Map")]),t._v(") is an in-memory storage that links all objects currently loaded in memory to their primary key IDs. You can retrieve one of these objects through "),a("code",[t._v("Session.get()")]),t._v(". This method searches for the object in the "),a("code",[t._v("ID Map")]),t._v(" if it's in memory, or through a "),a("code",[t._v("SELECT")]),t._v(" statement if it's not.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_squidward\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("An important point is that the "),a("code",[t._v("ID Map")]),t._v(" maintains unique objects among Python objects.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_squidward "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" squidward \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n")])])]),a("p",[t._v("The "),a("code",[t._v("ID Map")]),t._v(" is a crucial feature that allows manipulation of complex object sets within a transaction in an unsynchronized state.")]),t._v(" "),a("h3",{attrs:{id:"committing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#committing"}},[t._v("#")]),t._v(" Committing")]),t._v(" "),a("p",[t._v("We now "),a("code",[t._v("commit")]),t._v(" the current changes to the transaction.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nCOMMIT\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"how-to-update-orm-objects"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-to-update-orm-objects"}},[t._v("#")]),t._v(" How to UPDATE ORM objects")]),t._v(" "),a("p",[t._v("There are two ways to perform an "),a("code",[t._v("UPDATE")]),t._v(" through ORM:")]),t._v(" "),a("ol",[a("li",[t._v("Using the "),a("code",[t._v("unit of work")]),t._v(" pattern employed by "),a("code",[t._v("Session")]),t._v(". "),a("code",[t._v("UPDATE")]),t._v(" operations for each primary key with changes are sent out in sequence.")]),t._v(" "),a("li",[t._v('Known as "ORM usage update", where you can explicitly use the '),a("code",[t._v("Update")]),t._v(' construct with Session."')])]),t._v(" "),a("h3",{attrs:{id:"updating-changes-automatically"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#updating-changes-automatically"}},[t._v("#")]),t._v(" Updating changes automatically")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("filter_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'sandy\',)\n"""')]),t._v("\n")])])]),a("p",[t._v("This 'Sandy' user object acts as a "),a("em",[t._v("proxy")]),t._v(" for a row in the database, more specifically, for the row with primary key "),a("code",[t._v("2")]),t._v(" from the transaction's perspective.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Squirrel"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# When an object's attribute is changed, the Session records this change.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dirty "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Such changed objects are referred to as 'dirty' and can be checked in session.dirty.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n")])])]),a("p",[t._v("When the "),a("code",[t._v("Session")]),t._v(" executes "),a("code",[t._v("flush")]),t._v(", an "),a("code",[t._v("UPDATE")]),t._v(" is executed in the database, actually updating the values in the database. If a "),a("code",[t._v("SELECT")]),t._v(" statement is executed afterwards, a "),a("code",[t._v("flush")]),t._v(" is automatically executed, allowing you to immediately retrieve the updated name value of Sandy through "),a("code",[t._v("SELECT")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy_fullname "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=? WHERE user_account.id = ?\n[...] (\'Sandy Squirrel\', 2)\nSELECT user_account.fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (2,)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("sandy_fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nSandy Squirrel\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Using the flush, Sandy's changes are actually reflected in the database,")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# causing the object to lose its 'dirty' status.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dirty \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),t._v("\n")])])]),a("h3",{attrs:{id:"orm-usage-update"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-usage-update"}},[t._v("#")]),t._v(" ORM usage update")]),t._v(" "),a("p",[t._v("The last method to perform an "),a("code",[t._v("UPDATE")]),t._v(" through ORM is to explicitly use 'ORM usage update'. This allows you to use a general SQL "),a("code",[t._v("UPDATE")]),t._v(" statement that can affect many rows at once.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Squirrel Extraordinaire"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=? WHERE user_account.name = ?\n[...] (\'Sandy Squirrel Extraordinaire\', \'sandy\')\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("cursor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("object")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n")])])]),a("p",[t._v("If there are objects in the current "),a("code",[t._v("Session")]),t._v(" that match the given conditions, the corresponding "),a("code",[t._v("update")]),t._v(" will also be reflected in these objects.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Squirrel Extraordinaire'")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"how-to-delete-orm-objects"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-to-delete-orm-objects"}},[t._v("#")]),t._v(" How to Delete ORM objects")]),t._v(" "),a("p",[t._v("You can mark individual ORM objects for deletion using the "),a("code",[t._v("Session.delete()")]),t._v(" method. Once "),a("code",[t._v("delete")]),t._v(" is executed, objects in that "),a("code",[t._v("Session")]),t._v(" become expired.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" patrick "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (3,)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("patrick"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Indicate that patrick will be deleted")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"patrick"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Execute flush at this point")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.id AS address_id, address.email_address AS address_email_address,\naddress.user_id AS address_user_id\nFROM address\nWHERE ? = address.user_id\n[...] (3,)\nDELETE FROM user_account WHERE user_account.id = ?\n[...] (3,)\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'patrick\',)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Once expired in the Session, the object is removed from the session.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),t._v("\n")])])]),a("p",[t._v("Like the 'Sandy' used in the above "),a("code",[t._v("UPDATE")]),t._v(", these actions are only within the ongoing transaction and can be undone at any time unless "),a("em",[t._v("committed")]),t._v(".")]),t._v(" "),a("h3",{attrs:{id:"orm-usage-delete"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-usage-delete"}},[t._v("#")]),t._v(" ORM usage delete")]),t._v(" "),a("p",[t._v("Like "),a("code",[t._v("UPDATE")]),t._v(", there is also 'ORM usage delete'.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# This is just an example, not a necessary operation for delete.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (4,)\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"squidward"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account WHERE user_account.name = ?\n[...] (\'squidward\',)\n\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"rolling-back"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rolling-back"}},[t._v("#")]),t._v(" Rolling Back")]),t._v(" "),a("p",[a("code",[t._v("Session")]),t._v(" has a "),a("code",[t._v("Session.rollback()")]),t._v(" method to roll back the current operations. This method affects Python objects like the aforementioned "),a("code",[t._v("sandy")]),t._v(".\nCalling "),a("code",[t._v("Session.rollback()")]),t._v(" not only rolls back the transaction but also turns all objects associated with this "),a("code",[t._v("Session")]),t._v(" into "),a("code",[t._v("expired")]),t._v(" status. This state change triggers a self-refresh the next time the object is accessed, a process known as "),a("em",[t._v("lazy loading")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rollback"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nROLLBACK\n")])])]),a("p",[t._v("Looking closely at "),a("code",[t._v("sandy")]),t._v(", which is in the "),a("code",[t._v("expired")]),t._v(" state, you can see that no other information remains except for special SQLAlchemy-related status objects.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__dict__\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'_sa_instance_state'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("state"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("InstanceState "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("object")]),t._v(" at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Since the session is expired, accessing the object properties will trigger a new transaction.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (2,)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__dict__ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Now you can see that the database row is also filled in the sandy object.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'_sa_instance_state'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("state"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("InstanceState "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("object")]),t._v(" at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("For the deleted objects, you can see that they are restored in the "),a("code",[t._v("Session")]),t._v(" and appear again in the database.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" patrick "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" patrick\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'patrick\',)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"closing-the-session"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#closing-the-session"}},[t._v("#")]),t._v(" Closing the "),a("code",[t._v("Session")])]),t._v(" "),a("p",[t._v("We have handled the "),a("code",[t._v("Session")]),t._v(" outside of the context structure, and in such cases, it is good practice to "),a("em",[t._v("explicitly")]),t._v(" close the "),a("code",[t._v("Session")]),t._v(" as follows:")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("close"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nROLLBACK\n")])])]),a("p",[t._v("Similarly, when a "),a("code",[t._v("Session")]),t._v(" created through a context statement is closed within the context statement, the following actions are performed.")]),t._v(" "),a("ul",[a("li",[t._v("Cancel all ongoing transactions (e.g., rollbacks) to release all connection resources to the connection pool.\n"),a("ul",[a("li",[t._v("This means you don't need to explicitly call "),a("code",[t._v("Session.rollback()")]),t._v(" to check if the transaction was rolled back when closing the "),a("code",[t._v("Session")]),t._v(" after performing some read-only operations with it. The connection pool handles this.")])])]),t._v(" "),a("li",[t._v("Remove all objects from the "),a("code",[t._v("Session")]),t._v(".\n"),a("ul",[a("li",[t._v("This means that all Python objects loaded for this Session, such as "),a("code",[t._v("sandy")]),t._v(", "),a("code",[t._v("patrick")]),t._v(", and "),a("code",[t._v("squidward")]),t._v(", are now in a "),a("code",[t._v("detached")]),t._v(" state. For instance, an object that was in the "),a("code",[t._v("expired")]),t._v(" state is no longer associated with a database transaction to refresh data due to a "),a("code",[t._v("Session.commit()")]),t._v(" call, and it does not contain the current row's state.")]),t._v(" "),a("li",[a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\nTraceback "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("most recent call last"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nsqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("DetachedInstanceError"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Instance "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("User at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("not")]),t._v(" bound to a Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" attribute refresh operation cannot proceed\n")])])])]),t._v(" "),a("li",[t._v("Detached objects can be reassociated with the same or a new "),a("code",[t._v("Session")]),t._v(" using the "),a("code",[t._v("Session.add()")]),t._v(" method, re-establishing the relationship with a specific database row.")]),t._v(" "),a("li",[a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Reconnect to the session")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Retrieve the information through the transaction again.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (4,)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),t._v("\n")])])])])])])]),t._v(" "),a("blockquote",[a("p",[t._v("Objects in the "),a("code",[t._v("detached")]),t._v(" state should ideally be avoided. When a "),a("code",[t._v("Session")]),t._v(" is closed, it cleans up references to all previously connected objects. Typically, the need for "),a("code",[t._v("detached")]),t._v(" objects arises in web applications when an object has just been committed and the "),a("code",[t._v("Session")]),t._v(" is closed before it is rendered in a view. In this case, set the "),a("code",[t._v("Session.expire_on_commit")]),t._v(" flag to "),a("code",[t._v("False")]),t._v(".")])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/19.7b4a8a4e.js b/assets/js/19.7b4a8a4e.js new file mode 100644 index 0000000..48579dd --- /dev/null +++ b/assets/js/19.7b4a8a4e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{416:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"working-with-related-objects-using-orm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#working-with-related-objects-using-orm"}},[t._v("#")]),t._v(" Working with Related Objects Using ORM")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("In this chapter, we will cover another essential ORM concept, which is the interaction with mapped objects that reference other objects.")]),t._v(" "),a("p",[a("code",[t._v("relationship()")]),t._v(" defines the relationship between two mapped objects and is also known as "),a("strong",[t._v("self-referencing")]),t._v(".")]),t._v(" "),a("p",[t._v("For simplicity, we will omit "),a("code",[t._v("Column")]),t._v(" mappings and other directives, and explain "),a("code",[t._v("relationship()")]),t._v(" in a shortened form.")]),t._v(" "),a("br"),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" relationship\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ... Column mappings")]),t._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'address'")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ... Column mappings")]),t._v("\n\n user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"User"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("p",[t._v("In the structure shown, the "),a("code",[t._v("User")]),t._v(" object has a variable "),a("code",[t._v("addresses")]),t._v(", and the "),a("code",[t._v("Address")]),t._v(" object has a variable "),a("code",[t._v("user")]),t._v(".")]),t._v(" "),a("p",[t._v("Both are created as relationship objects, but these aren't "),a("strong",[t._v("actual database columns")]),t._v(" but are set up to allow "),a("strong",[t._v("easy access")]),t._v(" in the code.")]),t._v(" "),a("p",[t._v("In other words, it facilitates easy navigation from a "),a("code",[t._v("User")]),t._v(" object to an "),a("code",[t._v("Address")]),t._v(" object.")]),t._v(" "),a("p",[t._v("Additionally, the "),a("code",[t._v("back_populates")]),t._v(" parameter in the "),a("code",[t._v("relationship")]),t._v(" declaration allows for the reverse situation, i.e., navigating from an "),a("code",[t._v("Address")]),t._v(" object to a "),a("code",[t._v("User")]),t._v(" object.")]),t._v(" "),a("blockquote",[a("p",[t._v("In relational Database terms, it naturally sets a 1 : N relationship as an N : 1 relationship.")])]),t._v(" "),a("p",[t._v("In the next section, we will see what role the "),a("code",[t._v("relationship()")]),t._v(" object's instances play and how they function.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"using-related-objects"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-related-objects"}},[t._v("#")]),t._v(" Using Related Objects")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("When a new "),a("code",[t._v("User")]),t._v(" object is created, the "),a("code",[t._v(".addresses")]),t._v(" collection appears as a "),a("code",[t._v("List")]),t._v(" object.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("You can add an "),a("code",[t._v("Address")]),t._v(" object using "),a("code",[t._v("list.append()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pear1.krabs@gmail.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("append"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The u1.addresses collection now includes the new Address object.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("If an "),a("code",[t._v("Address")]),t._v(" object is associated with the "),a("code",[t._v("User.addresses")]),t._v(" collection, another action occurs in the variable "),a("code",[t._v("u1")]),t._v(". The User.addresses and Address.user relationship is synchronized, allowing you to move:\n- From a "),a("code",[t._v("User")]),t._v(" object to an "),a("code",[t._v("Address")]),t._v(", and\n- Back from an "),a("code",[t._v("Address")]),t._v(" object to a "),a("code",[t._v("User")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("This is the result of synchronization using "),a("code",[t._v("relationship.back_populates")]),t._v(" between the two "),a("code",[t._v("relationship()")]),t._v(" objects.")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("relationship()")]),t._v(" parameter can be complementarily assigned/list modified to another variable. Creating another "),a("code",[t._v("Address")]),t._v(" object and assigning it to the "),a("code",[t._v("Address.user")]),t._v(" property makes it part of the "),a("code",[t._v("User.addresses")]),t._v(" collection.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pearl@aol.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("p",[t._v("We actually used the variable "),a("code",[t._v("u1")]),t._v(" as a keyword argument for "),a("code",[t._v("user")]),t._v(" as if it were a property declared in the object ("),a("code",[t._v("Address")]),t._v("). It's equivalent to assigning the property afterward.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# equivalent effect as a2 = Address(user=u1)")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" u1\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"cascading-objects-in-the-session"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#cascading-objects-in-the-session"}},[t._v("#")]),t._v(" Cascading Objects in the "),a("code",[t._v("Session")])]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("We now have two related "),a("code",[t._v("User")]),t._v(" and "),a("code",[t._v("Address")]),t._v(" objects in a bidirectional structure in memory, but as mentioned earlier in "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/6. Manipulating Data Using ORM.html#inserting-rows-with-orm)"}},[t._v("Inserting Rows with ORM")]),t._v(" , these objects are in a "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/glossary.html#term-transient)"}},[t._v("transient")]),t._v(" state in the "),a("code",[t._v("Session")]),t._v(" until they are associated with it.")],1),t._v(" "),a("p",[t._v("We need to see when using "),a("code",[t._v("Session.add()")]),t._v(", and applying the method to the "),a("code",[t._v("User")]),t._v(" object, that the related "),a("code",[t._v("Address")]),t._v(" objects are also added.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a2 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),t._v("\n")])])]),a("p",[t._v("The three objects are now in a "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/glossary.html#term-pending)"}},[t._v("pending")]),t._v(" state, which means no "),a("code",[t._v("INSERT")]),t._v(" operations have been executed yet. The three objects have not been assigned primary keys, and the "),a("code",[t._v("a1")]),t._v(" and "),a("code",[t._v("a2")]),t._v(" objects have a column ("),a("code",[t._v("user_id")]),t._v(") reference property. This is because the objects are not yet actually connected to a real database.")],1),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),t._v("\n")])])]),a("p",[t._v("Let's save it to the database.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("If we translate the implemented code into SQL queries, it would look like this.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COMMIT")]),t._v("\n")])])]),a("p",[t._v("Using session, you can automate SQL "),a("code",[t._v("INSERT")]),t._v(", "),a("code",[t._v("UPDATE")]),t._v(", "),a("code",[t._v("DELETE")]),t._v(" statements.")]),t._v(" "),a("p",[t._v("Finally, executing "),a("code",[t._v("Session.commit()")]),t._v(" ensures all steps are called in the correct order, and the primary key of "),a("code",[t._v("address.user_id")]),t._v(" is applied in the "),a("code",[t._v("user_account")]),t._v(".")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"loading-relationships"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#loading-relationships"}},[t._v("#")]),t._v(" Loading Relationships")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("After calling "),a("code",[t._v("Session.commit()")]),t._v(", you can see the primary key created for the "),a("code",[t._v("u1")]),t._v(" object.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BEGIN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\nuser_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ?\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("You can also see that "),a("code",[t._v("id")]),t._v("s are now present in the objects linked to "),a("code",[t._v("u1.addresses")]),t._v(".")]),t._v(" "),a("p",[t._v("To retrieve these objects, we can observe the "),a("strong",[t._v("lazy load")]),t._v(" approach.")]),t._v(" "),a("blockquote",[a("p",[t._v("lazy loading : This is a method where a SELECT statement is executed to fetch information only when someone tries to access that information. In other words, it retrieves the necessary information as needed.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" ? "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("SQLAlchemy ORM’s default for collections and related properties is "),a("strong",[t._v("lazy loading")]),t._v(". This means once a collection has been "),a("em",[t._v("relationshipped")]),t._v(", as long as the data exists in memory, it remains accessible.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("Although lazy loading can be costly without explicit steps for optimization, it is optimized at least not to perform redundant operations.")]),t._v(" "),a("p",[t._v("You can also see the "),a("code",[t._v("a1")]),t._v(" and "),a("code",[t._v("a2")]),t._v(" objects in the "),a("code",[t._v("u1.addresses")]),t._v(" collection.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a1\nAddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" a2\nAddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("We will provide a further introduction to the concept of "),a("code",[t._v("relationship")]),t._v(" in the latter part of this section.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"using-relationship-in-queries"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-relationship-in-queries"}},[t._v("#")]),t._v(" Using "),a("code",[t._v("relationship")]),t._v(" in Queries")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("This section introduces several ways in which "),a("code",[t._v("relationship()")]),t._v(" helps automate SQL query construction.")]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"join-tables-using-relationship"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#join-tables-using-relationship"}},[t._v("#")]),t._v(" JOIN tables using "),a("code",[t._v("relationship()")])]),t._v(" "),a("p",[t._v("In "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#from절과-join-명시하기)"}},[t._v("Specifying the FROM and JOIN Clauses")]),t._v(" and "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#where절)"}},[t._v("WHERE Clauses")]),t._v(" sections, we used "),a("code",[t._v("Select.join()")]),t._v(" and "),a("code",[t._v("Select.join_from()")]),t._v(" methods to construct SQL JOINs. These methods infer the ON clause based on whether there's a "),a("code",[t._v("ForeignKeyConstraint")]),t._v(" object linking the two tables or provide specific SQL Expression syntax representing the "),a("code",[t._v("ON")]),t._v(" clause.")],1),t._v(" "),a("p",[a("code",[t._v("relationship()")]),t._v(" objects can be used to set the "),a("code",[t._v("ON")]),t._v(" clause for joins.\nA "),a("code",[t._v("relationship()")]),t._v(" corresponding object can be passed as a "),a("strong",[t._v("single argument")]),t._v(" to "),a("code",[t._v("Select.join()")]),t._v(", serving as both the right join and the ON clause.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n")])])]),a("p",[t._v("If "),a("code",[t._v("relationship()")]),t._v(" is not specified in "),a("code",[t._v("Select.join()")]),t._v(" or "),a("code",[t._v("Select.join_from()")]),t._v(", "),a("strong",[t._v("no ON clause is used")]),t._v(". This means it functions due to the "),a("code",[t._v("ForeignKeyConstraint")]),t._v(" between the two mapped table objects, not because of the "),a("code",[t._v("relationship()")]),t._v(" object of "),a("code",[t._v("User")]),t._v(" and "),a("code",[t._v("Address")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"joining-using-aliases-aliased"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#joining-using-aliases-aliased"}},[t._v("#")]),t._v(" Joining Using Aliases("),a("code",[t._v("aliased")]),t._v(")")]),t._v(" "),a("p",[t._v("When configuring SQL JOINs using "),a("code",[t._v("relationship()")]),t._v(", it's suitable to use [PropComparator.of_type()] with "),a("code",[t._v("aliased()")]),t._v(" cases. However, "),a("code",[t._v("relationship()")]),t._v(" is used to configure the same joins as described in ["),a("code",[t._v("ORM Entity Aliases")]),t._v("].")]),t._v(" "),a("p",[t._v("You can directly use "),a("code",[t._v("aliased()")]),t._v(" in a join with "),a("code",[t._v("relationship()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" aliased\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_2 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" address_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" :email_address_1\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("AND")]),t._v(" address_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" :email_address_2\n")])])]),a("p",[t._v("You can use join clause in "),a("code",[t._v("aliased()")]),t._v(" object using "),a("code",[t._v("relationship()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_1\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"expanding-on-conditions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#expanding-on-conditions"}},[t._v("#")]),t._v(" Expanding ON Conditions")]),t._v(" "),a("p",[t._v("You can add conditions to the ON clause created by "),a("code",[t._v("relation()")]),t._v(". This feature is useful not only for quickly limiting the scope of a specific join for a related path but also for use cases like loader strategy configuration introduced in the last section.\n"),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/14/orm/internals.html#sqlalchemy.orm.PropComparator.and_)"}},[a("code",[t._v("PropComparator.and_()")])]),t._v(" method allows a series of SQL expressions to be positionally combined in the JOIN's "),a("code",[t._v("ON")]),t._v(" clause via "),a("code",[t._v("AND")]),t._v(".\nFor example, to limit the ON criteria to specific email addresses using "),a("code",[t._v("User")]),t._v(" and "),a("code",[t._v("Address")]),t._v(", you would do this.")],1),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("AND")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ?\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"exists-has-and"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exists-has-and"}},[t._v("#")]),t._v(" EXISTS "),a("code",[t._v("has()")]),t._v(" , "),a("code",[t._v("and()")])]),t._v(" "),a("p",[t._v("In the "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#exists-서브쿼리들)"}},[t._v("EXISTS Subqueries")]),t._v(" section, the SQL EXISTS keyword was introduced along with the "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#스칼라-서브-쿼리-상호연관-쿼리)"}},[t._v("Scalar Subqueries, Correlated Queries")]),t._v(" section.\n"),a("code",[t._v("relationship()")]),t._v(" provides some help in commonly creating subqueries for relationships.")],1),t._v(" "),a("br"),t._v(" "),a("p",[t._v("For a 1:N (one-to-many) relationship like "),a("code",[t._v("User.addresses")]),t._v(", you can use "),a("code",[t._v("PropComparator.any()")]),t._v(" to create a subquery for the address table rejoining the "),a("code",[t._v("user_account")]),t._v(" table. This method allows optional WHERE criteria to limit the rows matching the subquery.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("EXISTS")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("AND")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Conversely, to find objects without related data, use "),a("code",[t._v("~User.addresses.any()")]),t._v(" to search for "),a("code",[t._v("User")]),t._v(" objects.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Patrick McStar'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Eugene H. Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("NOT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("EXISTS")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])]),a("p",[a("code",[t._v("PropComparator.has()")]),t._v(" works similarly to "),a("code",[t._v("PropComparator.any()")]),t._v(" but is used for N:1 (Many-to-one) relationships.\nFor instance, to find all "),a("code",[t._v("Address")]),t._v(' objects belonging to "pearl", you would use this method.')]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("has"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pkrabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("EXISTS")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("AND")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"relationship-operators"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#relationship-operators"}},[t._v("#")]),t._v(" Relationship Operators")]),t._v(" "),a("p",[t._v("Several types of SQL creation helpers come with "),a("code",[t._v("relationship()")]),t._v(":")]),t._v(" "),a("ul",[a("li",[t._v("N : 1 (Many-to-one) comparison\nYou can select rows where the foreign key of the target entity matches the primary key value of a specified object instance in an N:1 relationship.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" :param_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n")])])]),a("ul",[a("li",[t._v("NOT N : 1 (Many-to-one) comparison\nYou can use the not equal (!=) operator.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" :user_id_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("OR")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("IS")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("NULL")]),t._v("\n")])])]),a("ul",[a("li",[t._v("You can check if an object is included in a 1:N (one-to-many) collection.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("contains"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" :param_1\n")])])]),a("ul",[a("li",[t._v("You can check if an object in a 1:N relationship is part of a specific parent item. "),a("code",[t._v("with_parent()")]),t._v(" creates a comparison that returns rows referencing the given parent item, equivalent to using the "),a("code",[t._v("==")]),t._v(' operator."')])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" with_parent\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("with_parent"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" :param_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"types-of-relationship-loading"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#types-of-relationship-loading"}},[t._v("#")]),t._v(" Types of Relationship Loading")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("In the "),a("a",{attrs:{href:"#loading-relationships"}},[t._v("Loading Relationships")]),t._v(" section, we introduced the concept that when working with mapped object instances and accessing mapped attributes using "),a("code",[t._v("relationship()")]),t._v(", objects that should be in this collection are loaded, and if the collection is not filled, "),a("em",[t._v("lazy load")]),t._v(" occurs.")]),t._v(" "),a("p",[t._v("Lazy loading is one of the most famous ORM patterns and also the most controversial. If dozens of ORM objects in memory each refer to a few unloaded properties, the routine manipulation of objects can implicitly release many problems ("),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/glossary.html#term-N-plus-one-problem)"}},[a("code",[t._v("N+1 Problem")])]),t._v("), which can accumulate. Such implicit queries may not work at all when attempting database transformations that are no longer viable or when using alternative concurrency patterns like asynchronous.")],1),t._v(" "),a("blockquote",[a("p",[t._v("What is a "),a("a",{attrs:{href:"(https://blog.naver.com/yysdntjq/222405755893)"}},[a("code",[t._v("N + 1 Problem")])]),t._v("?\nIt's a problem where you fetch N records with one query, but to get the desired data, you end up performing a secondary query for each of these N records.")])]),t._v(" "),a("p",[t._v("Lazy loading is a very popular and useful pattern when it is compatible with the concurrency approach in use and does not cause other problems. For this reason, SQLAlchemy's ORM focuses on features that allow you to permit and optimize these load behaviors.")]),t._v(" "),a("p",[t._v("Above all, the first step to effectively using ORM's lazy loading is to "),a("strong",[t._v("test the Application and check the SQL")]),t._v(".\nIf inappropriate loads occur for objects detached from the "),a("code",[t._v("Session")]),t._v(", the use of "),a("strong",[a("a",{attrs:{href:"#types-of-relationship-loading"}},[a("code",[t._v("Types of Relationship Loading")])])]),t._v(" should be reviewed.")]),t._v(" "),a("p",[t._v("You can mark objects to be associated with a SELECT statement using the "),a("code",[t._v("Select.options()")]),t._v(" method.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" user_obj "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n user_obj"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# access addresses collection already loaded")]),t._v("\n")])])]),a("p",[t._v("You can also configure it as a default for "),a("code",[t._v("relationship()")]),t._v(" using "),a("code",[t._v("relationship.lazy")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" relationship\nclass "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(":\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),t._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"selectin"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("cf. "),a("strong",[t._v("Two Techniques of Relationship Loading")])]),t._v(" "),a("ul",[a("li",[a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html#relationship-lazy-option)"}},[a("code",[t._v("Configuring Loader Strategies at Mapping Time")])]),t._v(" "),a("ul",[a("li",[t._v("Details about "),a("code",[t._v("relationship()")]),t._v(" configuration")])])],1),t._v(" "),a("li",[a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html#relationship-loader-options)"}},[a("code",[t._v("Relationship Loading with Loader Options")])]),t._v(" "),a("ul",[a("li",[t._v("Details about the loader")])])],1)])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"select-in-loading-method"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#select-in-loading-method"}},[t._v("#")]),t._v(" Select IN loading Method")]),t._v(" "),a("p",[t._v("The most useful loading option in recent SQLAlchemy versions is "),a("code",[t._v("selectinload()")]),t._v('. This option solves the most common form of the "N+1 Problem" problem, which is an issue with sets of objects referencing related collections. It typically uses a SELECT form that can be sent out for the related table without introducing JOINs or subqueries and only queries for parent objects whose collections are not loaded.')]),t._v(" "),a("p",[t._v("The following example shows the Address objects related to a "),a("code",[t._v("User")]),t._v(" object being loaded with "),a("code",[t._v("selectinload()")]),t._v(". During the "),a("code",[t._v("Session.execute()")]),t._v(" call, two SELECT statements are generated in the database, with the second fetching the related "),a("code",[t._v("Address")]),t._v(" objects.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" selectinload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("select")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("row")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("in")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("session")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(":\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("f"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"{row.User.name} ({', '.join(a.email_address for a in row.User.addresses)})\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nspongebob "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("spongebob"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("@sqlalchemy.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsandy "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("sandy"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("@sqlalchemy.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sandy"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("@squirrelpower.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\npatrick "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsquidward "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nehkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\npkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("krabs"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("@gmail.com")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pearl"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("@aol.com")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("IN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"joined-loading-method"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#joined-loading-method"}},[t._v("#")]),t._v(" Joined Loading Method")]),t._v(" "),a("p",[a("em",[t._v("Joined Loading")]),t._v(", the oldest in SQLAlchemy, is a type of eager loading, also known as "),a("code",[t._v("joined eager loading")]),t._v('. It is best suited for loading objects in "N:1 relationships", as it performs a SELECT JOIN of the tables specified in '),a("code",[t._v("relationship()")]),t._v(", fetching all table data at once.")]),t._v(" "),a("p",[t._v("For example, where an "),a("code",[t._v("Address")]),t._v(" object has a connected user, an INNER JOIN can be used rather than an OUTER JOIN.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" joinedload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("joinedload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" innerjoin"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nspongebob@sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("org spongebob\nsandy@sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("org sandy\nsandy@squirrelpower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("org sandy\npearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com pkrabs\npearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com pkrabs\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\nuser_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[a("code",[t._v("joinedload()")]),t._v(" is also used for 1: N collections but should be evaluated case-by-case compared to other options like "),a("code",[t._v("selectinload()")]),t._v(" due to its nested collections and larger collections.")]),t._v(" "),a("p",[t._v("It's important to note that the WHERE and ORDER BY criteria of the SELECT query "),a("strong",[t._v("do not target the table rendered by "),a("code",[t._v("joinload()")])]),t._v(". In the SQL query above, you can see an "),a("strong",[t._v("anonymous alias")]),t._v(" applied to the "),a("code",[t._v("user_account")]),t._v(" table, which cannot directly address. This concept is further explained in the [Zen of joined Eager Loading] section.")]),t._v(" "),a("p",[t._v("The ON clause by "),a("code",[t._v("joinedload()")]),t._v(" can be directly influenced using the method described previously in "),a("a",{attrs:{href:"#expanding-on-conditions"}},[a("code",[t._v("Expanding ON Conditions")])]),t._v(".")]),t._v(" "),a("blockquote",[a("p",[t._v("cf.")]),t._v(" "),a("p",[t._v('In general cases, "N+1 problem" is much less prevalent, so many-to-one eager loading is often unnecessary.')]),t._v(" "),a("p",[t._v("When many objects all reference the same related object (e.g., many "),a("code",[t._v("Address")]),t._v(" objects referencing the same "),a("code",[t._v("User")]),t._v("), a single SQL for the "),a("code",[t._v("User")]),t._v(" object is emitted using ordinary lazy loading.")]),t._v(" "),a("p",[t._v("The lazy loading routine queries the related object by the current primary key without emitting SQL if possible.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"explicit-join-eager-load-method"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#explicit-join-eager-load-method"}},[t._v("#")]),t._v(" Explicit Join + Eager Load Method")]),t._v(" "),a("p",[t._v("A common use case uses the "),a("code",[t._v("contains_eager()")]),t._v(" option, which is very similar to "),a("code",[t._v("joinedload()")]),t._v(" except it assumes you have set up the JOIN directly and instead marks additional columns in the COLUMNS clause that should be loaded into each object's related properties.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" contains_eager\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("contains_eager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\npearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com pkrabs\npearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com pkrabs\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ? "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("For instance, we filtered "),a("code",[t._v("user_account.name")]),t._v(" and loaded it into the returned "),a("code",[t._v("Address.user")]),t._v(" property. A separate application of "),a("code",[t._v("joinedload()")]),t._v(" would have unnecessarily created a twice-joined SQL query.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("joinedload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# SELECT has a JOIN and LEFT OUTER JOIN unnecessarily")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\nuser_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("LEFT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("OUTER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("JOIN")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" user_account_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ON")]),t._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" :name_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id\n")])])]),a("br"),t._v(" "),a("blockquote",[a("p",[t._v("cf.")]),t._v(" "),a("p",[a("strong",[t._v("Two Techniques of Relationship Loading")]),a("br"),t._v(" "),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html#zen-of-eager-loading)"}},[a("code",[t._v("Zen of joined Eager Loading")])])],1),t._v(" "),a("ul",[a("li",[t._v("Details about this loading method\n"),a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html#contains-eager)"}},[a("code",[t._v("Routing Explicit Joins/Statements into Eagerly Loaded Collections")])])],1),t._v(" "),a("li",[t._v("using "),a("code",[t._v("contains_eager()")])])])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"setting-loader-paths"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#setting-loader-paths"}},[t._v("#")]),t._v(" Setting Loader Paths")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("PropComparator.and_()")]),t._v(" method is actually generally usable for most loader options.")]),t._v(" "),a("p",[t._v("For example, if you want to reload usernames and email addresses from the "),a("code",[t._v("sqlalchemy.org")]),t._v(" domain, you can limit the conditions with "),a("code",[t._v("PropComparator.and_()")]),t._v(" applied to the arguments passed to "),a("code",[t._v("selectinload()")]),t._v(".")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" selectinload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("endswith"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sqlalchemy.org"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" execution_options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("populate_existing"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" (")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("', '")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" a "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(')"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nspongebob "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsandy "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("sandy@squirrelpower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("org"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\npatrick "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsquidward "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nehkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\npkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("pearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("The above code is equivalent to executing the following query.")])]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("AS")]),t._v(" address_email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WHERE")]),t._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("IN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("AND")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("NOT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("LIKE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'%'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("It's crucial to note the addition of the "),a("code",[t._v(".execution_options(populate_existing=True)")]),t._v(" "),a("strong",[t._v("option")]),t._v(" above. When fetching rows, this option indicates that loader options must replace the existing collections' contents in already loaded objects.")]),t._v(" "),a("p",[t._v("Since we are iterating with a "),a("code",[t._v("Session")]),t._v(" object, the objects being loaded here are the same Python instances as those initially maintained at the start of this tutorial's ORM section.")]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"raise-loading-method"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#raise-loading-method"}},[t._v("#")]),t._v(" Raise Loading Method")]),t._v(" "),a("p",[t._v("The "),a("code",[t._v("raiseload()")]),t._v(' option is commonly used to completely block the occurrence of the "N+1 problem" by instead causing errors rather than slow loading.')]),t._v(" "),a("p",[t._v('There are two variants: blocking all "load" operations that include works that need SQL ('),a("em",[t._v("lazy load")]),t._v(") and those that only reference the current "),a("code",[t._v("Session")]),t._v(" ("),a("code",[t._v("raiseload.sql_only")]),t._v(" "),a("strong",[t._v("option")]),t._v(").")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ... Column mappings")]),t._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"raise_on_sql"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'address'")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ... Column mappings")]),t._v("\n\n user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"User"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"raise_on_sql"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("Using such mappings blocks the application from 'lazy loading', requiring you to specify loader strategies for specific queries.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[t._v("u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nu1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses\nsqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("InvalidRequestError"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'User.addresses'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("not")]),t._v(" available due to lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'raise_on_sql'")]),t._v("\n")])])]),a("p",[t._v("The exception indicates that the collection must be loaded first.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[t._v("u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("The "),a("code",[t._v('lazy="raise_on_sql"')]),t._v(" option is also wisely attempted for N:1 relationships.")]),t._v(" "),a("p",[t._v("Above, although the "),a("code",[t._v("Address.user")]),t._v(" property was not loaded into "),a("code",[t._v("Address")]),t._v(', "raiseload" does not cause an error because the corresponding '),a("code",[t._v("User")]),t._v(" object is in the same "),a("code",[t._v("Session")]),t._v(".")]),t._v(" "),a("blockquote",[a("p",[t._v("cf.")]),t._v(" "),a("p",[a("RouterLink",{attrs:{to:"/en/tutorial/(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html#prevent-lazy-with-raiseload)"}},[t._v("Preventing unwanted lazy loading with "),a("code",[t._v("raiseload")])]),a("br"),t._v(" "),a("a",{attrs:{href:"(https://docs.sqlalchemy.org/en/20/orm/loading_relationships.html)"}},[t._v("Preventing lazy loading in "),a("code",[t._v("relationship")])])],1)])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/2.98979e96.js b/assets/js/2.98979e96.js new file mode 100644 index 0000000..3b8dcc4 --- /dev/null +++ b/assets/js/2.98979e96.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{346:function(t,e,n){"use strict";n.d(e,"d",(function(){return i})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return h})),n.d(e,"e",(function(){return f})),n.d(e,"k",(function(){return p})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return v})),n.d(e,"j",(function(){return m}));n(31),n(85),n(347),n(113),n(349),n(197),n(84),n(116),n(7),n(117),n(39),n(118),n(190);var i=/#.*$/,r=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(i,"").replace(r,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(u(t))return t;var e=t.match(i),n=e?e[0]:"",r=o(t);return a.test(r)?t:r+".html"+n}function f(t,e){var n=decodeURIComponent(t.hash),r=function(t){var e=t.match(i);if(e)return e[0]}(e);return(!r||n===r)&&o(t.path)===o(e)}function p(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var i=t.charAt(0);if("/"===i)return t;if("?"===i||"#"===i)return e+t;var r=e.split("/");n&&r[r.length-1]||r.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return p(n,e,i);if(Array.isArray(e))return Object.assign(p(n,e[0],i),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(p(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},347:function(t,e,n){"use strict";var i=n(11),r=n(194),a=n(8),s=n(86),o=n(17),u=n(32),l=n(57),c=n(195),h=n(196);r("match",(function(t,e,n){return[function(e){var n=u(this),r=null==e?void 0:l(e,t);return r?i(r,e,n):new RegExp(e)[t](o(n))},function(t){var i=a(this),r=o(t),u=n(e,i,r);if(u.done)return u.value;if(!i.global)return h(i,r);var l=i.unicode;i.lastIndex=0;for(var f,p=[],d=0;null!==(f=h(i,r));){var g=o(f[0]);p[d]=g,""===g&&(i.lastIndex=c(r,s(i.lastIndex),l)),d++}return 0===d?null:p}]}))},348:function(t,e){t.exports="\t\n\v\f\r                 \u2028\u2029\ufeff"},349:function(t,e,n){"use strict";var i=n(36),r=n(11),a=n(2),s=n(194),o=n(191),u=n(8),l=n(32),c=n(121),h=n(195),f=n(86),p=n(17),d=n(57),g=n(199),v=n(196),m=n(88),b=n(189),k=n(3),_=b.UNSUPPORTED_Y,x=Math.min,C=[].push,y=a(/./.exec),$=a(C),L=a("".slice);s("split",(function(t,e,n){var a;return a="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var a=p(l(this)),s=void 0===n?4294967295:n>>>0;if(0===s)return[];if(void 0===t)return[a];if(!o(t))return r(e,a,t,s);for(var u,c,h,f=[],d=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),v=0,b=new RegExp(t.source,d+"g");(u=r(m,b,a))&&!((c=b.lastIndex)>v&&($(f,L(a,v,u.index)),u.length>1&&u.index=s));)b.lastIndex===u.index&&b.lastIndex++;return v===a.length?!h&&y(b,"")||$(f,""):$(f,L(a,v)),f.length>s?g(f,0,s):f}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:r(e,this,t,n)}:e,[function(e,n){var i=l(this),s=null==e?void 0:d(e,t);return s?r(s,e,i,n):r(a,p(i),e,n)},function(t,i){var r=u(this),s=p(t),o=n(a,r,s,i,a!==e);if(o.done)return o.value;var l=c(r,RegExp),d=r.unicode,g=(r.ignoreCase?"i":"")+(r.multiline?"m":"")+(r.unicode?"u":"")+(_?"g":"y"),m=new l(_?"^(?:"+r.source+")":r,g),b=void 0===i?4294967295:i>>>0;if(0===b)return[];if(0===s.length)return null===v(m,s)?[s]:[];for(var k=0,C=0,y=[];C@^][^\s!#%&*+<=>@^]*>/,N=/a/g,A=/a/g,D=new L(N)!==N,U=g.MISSED_STICKY,H=g.UNSUPPORTED_Y,W=i&&(!D||U||C||y||m((function(){return A[$]=!1,L(N)!=N||L(A)==A||"/a/i"!=L(N,"i")})));if(s("RegExp",W)){for(var G=function(t,e){var n,i,r,a,s,l,c=h(w,this),d=f(t),g=void 0===e,v=[],m=t;if(!c&&d&&g&&t.constructor===G)return t;if((d||h(w,t))&&(t=t.source,g&&(e="flags"in m?m.flags:S(m))),t=void 0===t?"":p(t),e=void 0===e?"":p(e),m=t,C&&"dotAll"in N&&(i=!!e&&R(e,"s")>-1)&&(e=j(e,/s/g,"")),n=e,U&&"sticky"in N&&(r=!!e&&R(e,"y")>-1)&&H&&(e=j(e,/y/g,"")),y&&(t=(a=function(t){for(var e,n=t.length,i=0,r="",a=[],s={},o=!1,u=!1,l=0,c="";i<=n;i++){if("\\"===(e=E(t,i)))e+=E(t,++i);else if("]"===e)o=!1;else if(!o)switch(!0){case"["===e:o=!0;break;case"("===e:I(P,T(t,i+1))&&(i+=2,u=!0),r+=e,l++;continue;case">"===e&&u:if(""===c||b(s,c))throw new O("Invalid capture group name");s[c]=!0,a[a.length]=[c,l],u=!1,c="";continue}u?c+=e:r+=e}return[r,a]}(t))[0],v=a[1]),s=o(L(t,e),c?this:w,G),(i||r||v.length)&&(l=k(s),i&&(l.dotAll=!0,l.raw=G(function(t){for(var e,n=t.length,i=0,r="",a=!1;i<=n;i++)"\\"!==(e=E(t,i))?a||"."!==e?("["===e?a=!0:"]"===e&&(a=!1),r+=e):r+="[\\s\\S]":r+=e+E(t,++i);return r}(t),n)),r&&(l.sticky=!0),v.length&&(l.groups=v)),t!==m)try{u(s,"source",""===m?"(?:)":m)}catch(t){}return s},B=function(t){t in G||l(G,t,{configurable:!0,get:function(){return L[t]},set:function(e){L[t]=e}})},M=c(L),q=0;M.length>q;)B(M[q++]);w.constructor=G,G.prototype=w,v(r,"RegExp",G)}_("RegExp")},354:function(t,e,n){var i=n(0),r=n(9),a=n(193),s=n(23),o=n(12).f,u=n(33).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"dotAll",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).dotAll;throw c("Incompatible receiver, RegExp required")}}})},355:function(t,e,n){var i=n(0),r=n(9),a=n(189).MISSED_STICKY,s=n(23),o=n(12).f,u=n(33).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"sticky",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).sticky;throw c("Incompatible receiver, RegExp required")}}})},356:function(t,e,n){"use strict";var i=n(2),r=n(87).PROPER,a=n(15),s=n(8),o=n(34),u=n(17),l=n(3),c=n(192),h=RegExp.prototype,f=h.toString,p=i(c),d=l((function(){return"/a/b"!=f.call({source:"a",flags:"b"})})),g=r&&"toString"!=f.name;(d||g)&&a(RegExp.prototype,"toString",(function(){var t=s(this),e=u(t.source),n=t.flags;return"/"+e+"/"+u(void 0===n&&o(h,t)&&!("flags"in h)?p(t):n)}),{unsafe:!0})},357:function(t,e,n){},358:function(t,e,n){},359:function(t,e,n){},360:function(t,e,n){},361:function(t,e,n){},362:function(t,e,n){},363:function(t,e){t.exports=function(t){return null==t}},364:function(t,e,n){},365:function(t,e,n){},366:function(t,e,n){},367:function(t,e,n){},368:function(t,e,n){},369:function(t,e,n){},373:function(t,e,n){"use strict";n.r(e);n(114),n(7);var i=n(346),r={name:"SidebarGroup",components:{DropdownTransition:n(374).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(373).default},methods:{isActive:i.e}},a=(n(393),n(56)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(394),n(31),n(113),n(84);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,f=c.sidebarDepth,p=Object(i.e)(a,h.path),d="auto"===h.type?p||h.children.some((function(t){return Object(i.e)(a,h.basePath+"#"+t.slug)})):p,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[r.frontmatter.sidebarDepth,f,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!i.d.test(h.path)?[g,u(t,Object(i.c)(h.headers),h.path,a,v)]:g}};n(395);function c(t,e){if("group"===e.type){var n=e.path&&Object(i.e)(t,e.path),r=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}));return n||r}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},f=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=f.exports},374:function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(385),n(56)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},375:function(t,e,n){"use strict";var i=n(1),r=n(376);i({target:"String",proto:!0,forced:n(377)("link")},{link:function(t){return r(this,"a","href",t)}})},376:function(t,e,n){var i=n(2),r=n(32),a=n(17),s=/"/g,o=i("".replace);t.exports=function(t,e,n,i){var u=a(r(t)),l="<"+e;return""!==n&&(l+=" "+n+'="'+o(a(i),s,""")+'"'),l+">"+u+""}},377:function(t,e,n){var i=n(3);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},378:function(t,e,n){"use strict";n(350)},379:function(t,e,n){var i=n(1),r=n(380);i({global:!0,forced:parseInt!=r},{parseInt:r})},380:function(t,e,n){var i=n(0),r=n(3),a=n(2),s=n(17),o=n(351).trim,u=n(348),l=i.parseInt,c=i.Symbol,h=c&&c.iterator,f=/^[+-]?0x/i,p=a(f.exec),d=8!==l(u+"08")||22!==l(u+"0x16")||h&&!r((function(){l(Object(h))}));t.exports=d?function(t,e){var n=o(s(t));return l(n,e>>>0||(p(f,n)?16:10))}:l},381:function(t,e,n){var i=n(87).PROPER,r=n(3),a=n(348);t.exports=function(t){return r((function(){return!!a[t]()||"​…᠎"!=="​…᠎"[t]()||i&&a[t].name!==t}))}},382:function(t,e,n){"use strict";var i,r=n(1),a=n(2),s=n(35).f,o=n(86),u=n(17),l=n(122),c=n(32),h=n(123),f=n(18),p=a("".endsWith),d=a("".slice),g=Math.min,v=h("endsWith");r({target:"String",proto:!0,forced:!!(f||v||(i=s(String.prototype,"endsWith"),!i||i.writable))&&!v},{endsWith:function(t){var e=u(c(this));l(t);var n=arguments.length>1?arguments[1]:void 0,i=e.length,r=void 0===n?i:g(o(n),i),a=u(t);return p?p(e,a,r):d(e,r-a.length,r)===a}})},383:function(t,e,n){"use strict";n(357)},384:function(t,e,n){"use strict";n(358)},385:function(t,e,n){"use strict";n(359)},386:function(t,e,n){"use strict";n(360)},387:function(t,e,n){"use strict";n(361)},388:function(t,e,n){"use strict";n(362)},389:function(t,e,n){"use strict";n(364)},390:function(t,e,n){var i=n(41),r=n(20),a=n(37);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},391:function(t,e,n){"use strict";n(365)},392:function(t,e,n){"use strict";n(366)},393:function(t,e,n){"use strict";n(367)},394:function(t,e,n){"use strict";var i=n(1),r=n(40).find,a=n(119),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),i({target:"Array",proto:!0,forced:s},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},395:function(t,e,n){"use strict";n(368)},396:function(t,e,n){"use strict";n(369)},400:function(t,e,n){"use strict";n.r(e);n(375),n(114),n(7),n(115);var i=n(346),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(56),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(378),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):n("Content",{staticClass:"footer",attrs:{"slot-key":"footer"}})],1)}),[],!1,null,null,null).exports),l=(n(379),n(352),n(190),n(118),n(39),n(31),n(347),n(202),n(203),n(197),n(85),n(353),n(354),n(355),n(356),n(84),n(349),n(113),n(382),n(205)),c=n.n(l),h=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=c()(e,"title","");return c()(e,"frontmatter.tags")&&(i+=" ".concat(e.frontmatter.tags.join(" "))),n&&(i+=" ".concat(n)),f(t,i)},f=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},i=new RegExp("[^\0-]"),r=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(i.test(t))return r.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(r.map((function(t,e){return r.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},p={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===i&&this.isSearchable(s))if(h(t,s))r.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&h(t,s,u.title)&&r.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return r}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),g=(n(384),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),v=n(54),m=(n(204),n(374)),b=n(206),k=n.n(b),_={name:"DropdownLink",components:{NavLink:s,DropdownTransition:m.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return k()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},x=(n(386),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(_,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(v.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),G=Object(a.a)(W,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=G.exports}}]); \ No newline at end of file diff --git a/assets/js/20.adec2767.js b/assets/js/20.adec2767.js new file mode 100644 index 0000000..d62019c --- /dev/null +++ b/assets/js/20.adec2767.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{414:function(t,e,o){"use strict";o.r(e);var r=o(56),n=Object(r.a)({},(function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[o("h1",{attrs:{id:"tutorial"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#tutorial"}},[t._v("#")]),t._v(" Tutorial")]),t._v(" "),o("p",[t._v("This document is a translated and organized version of the "),o("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SQLAlchemy 1.4/2.0 Tutorial"),o("OutboundLink")],1),t._v(".")]),t._v(" "),o("p",[t._v("The original official documentation is challenging to navigate and contains an overwhelming amount of information. Furthermore, it can be quite difficult for beginners to understand."),o("br"),t._v("\nWith this in mind, we thought of translating and organizing the SQLAlchemy Tutorial documents for easier comprehension and accessibility. The idea originated from "),o("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/issues/2",target:"_blank",rel:"noopener noreferrer"}},[t._v("this post"),o("OutboundLink")],1),t._v(", where people gathered to work together on this project.")]),t._v(" "),o("p",[t._v("Over a little more than a month, we took turns each week to work on a chapter of the official Tutorial document."),o("br"),t._v("\nWe reviewed each other's work, refining the articles and asking questions about parts we didn't understand."),o("br"),t._v("\nThese documents are the results of such efforts and also represent the traces of our study.")]),t._v(" "),o("p",[t._v("There are still many imperfections, and there might be errors."),o("br"),t._v("\nIf you find such issues, please feel free to contribute. Your participation is always welcome.")]),t._v(" "),o("p",[t._v("The following individuals have contributed to this project:")]),t._v(" "),o("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/graphs/contributors"}},[o("img",{attrs:{src:"https://contrib.rocks/image?repo=SoogoonSoogoonPythonists/sqlalchemy-for-pythonist"}})])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/21.c59b443d.js b/assets/js/21.c59b443d.js new file mode 100644 index 0000000..80f90c5 --- /dev/null +++ b/assets/js/21.c59b443d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{425:function(t,e,n){"use strict";n.r(e);var s=n(56),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/22.f84628fa.js b/assets/js/22.f84628fa.js new file mode 100644 index 0000000..ded9023 --- /dev/null +++ b/assets/js/22.f84628fa.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{417:function(t,a,s){"use strict";s.r(a);var r=s(56),e=Object(r.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"튜토리얼-개요"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#튜토리얼-개요"}},[t._v("#")]),t._v(" 튜토리얼 개요")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"개요"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#개요"}},[t._v("#")]),t._v(" 개요")]),t._v(" "),s("p",[t._v("SQLAlchemy는 Python에서 데이터베이스와의 연결 및 ORM 등을 활용할 수 있도록 해주는 라이브러리 입니다."),s("br"),t._v("\n가령 특정 쿼리를 코드에서 실행할 수 있고, ORM 객체를 통해 데이터베이스에서의 일련의 작업들을 수행할 수 있습니다.")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"설치"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#설치"}},[t._v("#")]),t._v(" 설치")]),t._v(" "),s("p",[t._v("SQLAlchemy는 다음처럼 설치할 수 있습니다.")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ pip "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" sqlalchemy\n")])])]),s("p",[t._v("사용하고 있는 버전은 다음과 같습니다.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" sqlalchemy\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sqlalchemy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__version__ \n"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.4")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".20")]),t._v("\n")])])]),s("br"),t._v(" "),s("h2",{attrs:{id:"제공되는-것"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#제공되는-것"}},[t._v("#")]),t._v(" 제공되는 것")]),t._v(" "),s("p",[t._v("SQLAlchemy는 다음처럼 2가지로 제공됩니다.")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("Core")]),t._v(" "),s("ul",[s("li",[t._v("데이터베이스 도구 키트로, SQLAlchemy의 기본 아키텍처입니다.")]),t._v(" "),s("li",[t._v("데이터베이스에 대한 연결을 관리하고, 데이터베이스 쿼리 및 결과와 상호 작용하고, SQL 문을 프로그래밍 방식으로 구성하기위한 도구를 제공합니다.")])])]),t._v(" "),s("li",[s("strong",[t._v("ORM")]),t._v(" "),s("ul",[s("li",[t._v("Core를 기반으로 구축되어 선택적 "),s("strong",[t._v("ORM")]),t._v(" 기능을 제공 합니다.")])])])]),t._v(" "),s("p",[t._v("기본적으로 Core에 대해 먼저 이해한 후, ORM을 사용하는게 좋습니다."),s("br"),t._v("\n튜토리얼 역시 Core부터 설명합니다.")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/23.2c4a7cf3.js b/assets/js/23.2c4a7cf3.js new file mode 100644 index 0000000..8a7937a --- /dev/null +++ b/assets/js/23.2c4a7cf3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{418:function(t,e,s){"use strict";s.r(e);var a=s(56),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"연결-설정하기"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#연결-설정하기"}},[t._v("#")]),t._v(" 연결 설정하기")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"데이터베이스와-연결하기"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#데이터베이스와-연결하기"}},[t._v("#")]),t._v(" 데이터베이스와 연결하기")]),t._v(" "),s("p",[t._v("비교적 가벼운 데이터베이스인 SQLite에 연결하는 작업을 해봅시다."),s("br"),t._v("\n다음처럼 해볼 수 있습니다.")]),t._v(" "),s("div",{staticClass:"language-python extra-class"},[s("pre",{pre:!0,attrs:{class:"language-python"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" create_engine\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" engine "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" create_engine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sqlite+pysqlite:///:memory:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" echo"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" future"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("ul",[s("li",[s("code",[t._v("sqlalchemy.create_engine")]),t._v(" 함수를 이용하여 데이터베이스와 연결을 맺는 "),s("strong",[t._v("'엔진'")]),t._v(" 을 만듭니다.")]),t._v(" "),s("li",[t._v("첫 번째 인자로 "),s("strong",[s("code",[t._v("문자열 URL")])]),t._v(" 을 넘깁니다.\n"),s("ul",[s("li",[t._v("일반적으로 "),s("code",[t._v("문자열 URL")]),t._v(" 은 "),s("code",[t._v("dialect+driver://username:password@host:port/database")]),t._v(" 의 형태로 구성됩니다.\n"),s("ul",[s("li",[s("code",[t._v("driver")]),t._v(" 값을 주지 않으면 "),s("code",[t._v("sqlalchemy")]),t._v(" 의 기본 설정 값이 들어가게 됩니다.")])])]),t._v(" "),s("li",[t._v("여기서는 "),s("code",[t._v("sqlite+pysqlite:///test.db")]),t._v(" 가 "),s("code",[t._v("문자열 URL")]),t._v(" 입니다.\n"),s("ul",[s("li",[s("code",[t._v("sqlite")]),t._v(" 의 경우 "),s("code",[t._v("sqlite:///")]),t._v(" 의 포맷을 따릅니다.")])])])])]),t._v(" "),s("li",[t._v("문자열 "),s("code",[t._v("URL")]),t._v(" 인 "),s("code",[t._v("sqlite:///test.db")]),t._v(" 에서 다음 정보들을 알 수 있습니다.\n"),s("ul",[s("li",[s("strong",[t._v("어떤 데이터베이스")]),t._v("를 사용할 것인지 ("),s("code",[t._v("dialect")]),t._v(" 라고 하며, 이 경우 "),s("code",[t._v("sqlite")]),t._v(" 입니다)")]),t._v(" "),s("li",[s("strong",[t._v("어떤 데이터베이스 API")]),t._v(" (DB와 상호작용하는 드라이버) 를 사용할 것인지 (이 경우 "),s("code",[t._v("pysqlite")]),t._v(" 입니다)")]),t._v(" "),s("li",[t._v("데이터베이스를 "),s("strong",[t._v("어떻게 찾을지")]),t._v(" (이 경우 "),s("code",[t._v("sqlite")]),t._v(" 에서 제공하는 인메모리를 사용합니다.)")])])]),t._v(" "),s("li",[s("code",[t._v("echo")]),t._v(" 파라미터의 값을 "),s("code",[t._v("True")]),t._v(" 를 주면 실행되는 모든 SQL을 출력해줍니다.")])]),t._v(" "),s("p",[t._v("엔진을 만들었지만, 아직 실제로 연결을 시도한 것은 아닙니다. 실제 연결은 데이터베이스에 대해 작업을 수행하라는 요청을 처음받을 때만 발생합니다.")])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/24.7785bb30.js b/assets/js/24.7785bb30.js new file mode 100644 index 0000000..2cecd08 --- /dev/null +++ b/assets/js/24.7785bb30.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{420:function(t,s,a){"use strict";a.r(s);var n=a(56),p=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"트랜잭션과-쿼리-실행하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#트랜잭션과-쿼리-실행하기"}},[t._v("#")]),t._v(" 트랜잭션과 쿼리 실행하기")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"연결-얻기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#연결-얻기"}},[t._v("#")]),t._v(" 연결 얻기")]),t._v(" "),a("p",[t._v("다음처럼 데이터베이스에 연결하여 쿼리를 실행할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" text\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"select 'hello world'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'hello world'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("ul",[a("li",[a("code",[t._v("engine.connect()")]),t._v(" 으로 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Connection")]),a("OutboundLink")],1),t._v(" 객체를 얻어 "),a("code",[t._v("conn")]),t._v(" 에 담습니다.\n"),a("ul",[a("li",[t._v("이 "),a("code",[t._v("Connection")]),t._v(" 객체를 통해 데이터베이스와 상호작용할 수 있습니다.")]),t._v(" "),a("li",[a("code",[t._v("with ...")]),t._v(" 구문은 하나의 트랜잭션 단위가 됩니다.")])])]),t._v(" "),a("li",[a("strong",[t._v("트랜잭션은 자동으로 커밋되지 않습니다.")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("Connection.commit()")]),t._v(" 을 호출해야 커밋됩니다.")])])])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"변경-사항-커밋하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#변경-사항-커밋하기"}},[t._v("#")]),t._v(" 변경 사항 커밋하기")]),t._v(" "),a("p",[t._v("연결을 얻고, 트랜잭션을 연 뒤 데이터베이스와 상호작용하는 일들은 자동으로 커밋되지 않습니다."),a("br"),t._v("\n커밋을 하려면 다음처럼 "),a("strong",[a("code",[t._v("Connection.commit()")])]),t._v(" 을 호출해야 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 테이블을 생성합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"CREATE TABLE some_table (x int, y int)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 데이터를 삽입합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 위 변경사항을 커밋합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("위 코드의 실행하면 다음과 같은 결과가 출력됩니다.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BEGIN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CREATE")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("TABLE")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COMMIT")]),t._v("\n")])])]),a("p",[a("strong",[a("code",[t._v("Engine.begin()")])]),t._v(" 으로 트랜잭션 종료시 자동으로 커밋을 찍게할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("begin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 트랜잭션 (컨텍스트 구문)이 끝나면 커밋됩니다.")]),t._v("\n")])])]),a("p",[t._v("위 코드의 실행하면 다음과 같은 결과가 출력됩니다.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BEGIN")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("engine")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("cursor")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("CursorResult object at "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COMMIT")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"명령문-실행의-기초"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#명령문-실행의-기초"}},[t._v("#")]),t._v(" 명령문 실행의 기초")]),t._v(" "),a("p",[t._v("다음처럼 쿼리를 실행하고 그 결과를 받아올 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# conn.execute() 는 Result라는 객체에 내보냅니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n")])])]),a("ul",[a("li",[a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Result",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Result")]),a("OutboundLink")],1),t._v(" 객체는 "),a("code",[t._v("conn.execute()")]),t._v(" 가 반환해주는 "),a("strong",[t._v('"쿼리 결과"를 들고 있는 객체')]),t._v("입니다.\n"),a("ul",[a("li",[t._v("링크를 눌러보면 어떤 기능을 제공하는지 볼 수 있습니다.")]),t._v(" "),a("li",[t._v("예를 들면 "),a("code",[t._v("Result.all()")]),t._v(" 을 통해 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Row",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Row")]),a("OutboundLink")],1),t._v(" 객체의 리스트를 받을 수 있습니다.")])])])]),t._v(" "),a("blockquote",[a("p",[a("code",[t._v("Result")]),t._v(" 와 "),a("code",[t._v("Row")]),t._v(" 모두 sqlalchemy에서 제공하는 객체입니다.")])]),t._v(" "),a("p",[a("code",[t._v("Result")]),t._v(" 객체로 다음처럼 각 행에 액세스할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[t._v("result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select x, y from some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 튜플로 접근합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ...")]),t._v("\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 정수 인덱스로 접근합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 속성 이름으로 접근합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n y "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y\n \n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 매핑 액세스로 접근합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" dict_row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mappings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dict_row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'x'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n y "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" dict_row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'y'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"쿼리에-매개-변수-전달하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#쿼리에-매개-변수-전달하기"}},[t._v("#")]),t._v(" 쿼리에 매개 변수 전달하기")]),t._v(" "),a("p",[t._v("쿼리에 다음처럼 파라미터를 전달할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table WHERE y > :y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 콜론 형식(:)으로 받습니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 사전 형식으로 넘깁니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n")])])]),a("p",[t._v("다음처럼 여러 개의 매개 변수를 보낼수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"INSERT INTO some_table (x, y) VALUES (:x, :y)"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 사전의 리스트로 넘깁니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("위 코드는 다음과 같은 쿼리를 실행하게 됩니다.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/dbapi_transactions.html#bundling-parameters-with-a-statement",target:"_blank",rel:"noopener noreferrer"}},[t._v('"명령문으로 매개 변수 묶기"'),a("OutboundLink")],1),t._v(" 가 공식 문서에 나오지만, 이 부분은 저도 이해가 되지 않아 넘기겠습니다."),a("br"),t._v("\n추후 이해하신 분은 이 문서에 기여해주시면 감사하겠습니다.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"orm-session으로-실행"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-session으로-실행"}},[t._v("#")]),t._v(" ORM "),a("code",[t._v("Session")]),t._v("으로 실행")]),t._v(" "),a("p",[t._v("이번에는 "),a("code",[t._v("Connection")]),t._v(" 객체가 아니라 ORM에서 제공해주는 "),a("code",[t._v("Session")]),t._v(" 로 쿼리를 실행해봅시다."),a("br"),t._v("\n다음처럼 해볼 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Session\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("bindparams"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Session 객체에 Engine 객체의 인스턴스를 넘겨 데이터베이스와 상호작용할 수 있는 인스턴스를 얻습니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Session.execute() 메서드로 쿼리를 실행합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"x: ')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" y: ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("y"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[a("code",[t._v("Session")]),t._v(" 역시 종료 시에 자동으로 커밋을하지 않습니다. 커밋을 하려면 다음처럼 직접 "),a("code",[t._v("Session.commit()")]),t._v(" 을 호출해야 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"UPDATE some_table SET y=:y WHERE x=:x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"y"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 명시적으로 호출해야 합니다.")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/25.dc95a31e.js b/assets/js/25.dc95a31e.js new file mode 100644 index 0000000..55409fe --- /dev/null +++ b/assets/js/25.dc95a31e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{422:function(t,s,a){"use strict";a.r(s);var n=a(56),p=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"데이터베이스-메타데이터로-작업하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#데이터베이스-메타데이터로-작업하기"}},[t._v("#")]),t._v(" 데이터베이스 메타데이터로 작업하기")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("SQLAlchemy Core와 ORM은 파이썬 객체를 데이터베이스의 테이블과 컬럼처럼 사용할 수 있게 하기 위해서 만들어졌습니다. 이러한 것들을 데이터베이스 메타데이터로 사용할 수 있습니다.")]),t._v(" "),a("blockquote",[a("p",[t._v("메타데이터는 데이터를 기술하는 데이터를 설명합니다. 여기서 "),a("strong",[t._v("메타데이터는 구성된 테이블, 열, 제약 조건 및 기타 객체 정보 등을 말합니다.")])])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"테이블-객체를-만들고-메타데이터에-담기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#테이블-객체를-만들고-메타데이터에-담기"}},[t._v("#")]),t._v(" 테이블 객체를 만들고 메타데이터에 담기")]),t._v(" "),a("p",[t._v("관계형 데이터베이스에서는 쿼리를 통해 테이블을 만들지만, SQLAlchemy에서는 Python 객체를 통해 테이블을 만들 수 있습니다."),a("br"),t._v("\nSQLAlchemy 표현 언어를 시작할려면 사용할려는 데이터베이스 테이블을 "),a("code",[t._v("Table")]),t._v(" 객체로 만들어줘야합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" MetaData\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" metadata "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 테이블들의 메타 정보를 담게될 객체입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 데이터베이스에 저장될 table 이름입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 이 테이블에 들어갈 컬럼입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("ul",[a("li",[a("code",[t._v("Table")]),t._v(" 객체를 통해 데이터베이스 테이블을 만들 수 있습니다.")]),t._v(" "),a("li",[a("code",[t._v("Column")]),t._v("을 통해 테이블의 컬럼을 구현합니다.\n"),a("ul",[a("li",[t._v("기본적으로 "),a("code",[t._v("Column(컬럼 이름, 데이터 유형)")]),t._v(" 와 같이 정의합니다.")])])])]),t._v(" "),a("p",[a("code",[t._v("Table")]),t._v(" 인스턴스를 만들고나면 다음처럼 만들어진 컬럼 정보를 알 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-Python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\nColumn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("length"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("keys"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"단순-제약-선언하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#단순-제약-선언하기"}},[t._v("#")]),t._v(" 단순 제약 선언하기")]),t._v(" "),a("p",[t._v("우리는 위의 user 테이블을 만드는 코드에서 "),a("code",[t._v("Column('id', Integer, primary_key=True)")]),t._v(" 구문을 보았습니다."),a("br"),t._v("\n이는 "),a("code",[t._v("id")]),t._v(" 컬럼을 기본키로 둔다고 선언하는 것입니다."),a("br"),t._v("\n기본키는 암시적으로 "),a("code",[t._v("PrimaryKeyConstraint")]),t._v(" 객체에 구조로 선언되어있습니다. 이는 다음처럼 확인할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("primary_key\nPrimaryKeyConstraint"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("기본키와 더불어 외래키도 다음처럼 선언할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" ForeignKey\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_table "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ForeignKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account.id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ForeignKey 객체로 외래 키를 선언합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'email_address'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("ul",[a("li",[a("code",[t._v("ForeignKey('테이블 이름.외래 키')")]),t._v(" 형태로 외래 키 컬럼을 선언할 수 있습니다.\n"),a("ul",[a("li",[t._v("이 때 "),a("code",[t._v("Column")]),t._v(" 객체의 데이터타입을 생략할 수 있습니다. 데이터타입은 외래 키에 해당하는 컬럼을 찾아서 자동으로 추론됩니다.")])])]),t._v(" "),a("li",[t._v("따로 설명하지 않았지만, "),a("code",[t._v("nullable=False")]),t._v(" 파라미터와 값을 넘김으로써 컬럼에 "),a("code",[t._v("NOT NULL")]),t._v(" 제약 조건을 선언할 수 있습니다.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"데이터베이스에-적용하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#데이터베이스에-적용하기"}},[t._v("#")]),t._v(" 데이터베이스에 적용하기")]),t._v(" "),a("p",[t._v("지금까지 SQLAlchemy로 데이터베이스 테이블을 선언했습니다. 이제 이렇게 선언한 테이블이 실제 데이터베이스에 생성되도록 해봅시다."),a("br"),t._v("\n다음처럼 "),a("code",[t._v("metadata.create_all()")]),t._v(" 을 실행합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 위 코드는 `metadata` 인스턴스에 기록된 모든 테이블들을 생성합니다. ")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 결과적으로는 아래 쿼리를 실행하게 됩니다.")]),t._v("\n\nBEGIN "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_account"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nPRAGMA main"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCREATE TABLE user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" INTEGER NOT NULL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n name VARCHAR"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n fullname VARCHAR"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n PRIMARY KEY "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCREATE TABLE address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" INTEGER NOT NULL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n user_id INTEGER NOT NULL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n email_address VARCHAR NOT NULL"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n PRIMARY KEY "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n FOREIGN KEY"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" REFERENCES user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nCOMMIT\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"orm-방식으로-테이블-메타데이터-정의하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-방식으로-테이블-메타데이터-정의하기"}},[t._v("#")]),t._v(" ORM 방식으로 테이블 메타데이터 정의하기")]),t._v(" "),a("p",[t._v("위의 데이터베이스 구조를 만들고 제약조건을 똑같이 사용하지만, 이번에는 ORM 방식으로 진행해보겠습니다.")]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"레지스트리-설정하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#레지스트리-설정하기"}},[t._v("#")]),t._v(" 레지스트리 설정하기")]),t._v(" "),a("p",[t._v("먼저 다음처럼 "),a("code",[t._v("registry")]),t._v(" 객체를 만듭니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" registry\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[a("code",[t._v("registery")]),t._v(" 객체는 "),a("code",[t._v("MetaData")]),t._v(" 객체를 포함하고 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata\nMetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("이제 다음을 실행합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mapper_registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("generate_base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("위 과정을 다음처럼 "),a("code",[t._v("declarative_base")]),t._v(" 로 한 번에 할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" declarative_base\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" declarative_base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-객체-선언하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-객체-선언하기"}},[t._v("#")]),t._v(" ORM 객체 선언하기")]),t._v(" "),a("p",[a("code",[t._v("Base")]),t._v(" 객체를 상속받는 하위 객체를 정의함으로써 ORM 방식으로 데이터베이스의 테이블을 선언할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" relationship\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 데이터베이스에서 사용할 테이블 이름입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" fullname "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("__repr__")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"User(id=')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(", name=")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(", fullname=")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(')"')])]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Address")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'address'")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ForeignKey"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account.id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"User"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("__repr__")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"Address(id=')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(", email_address=")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("self"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token conversion-option punctuation"}},[t._v("!r")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(')"')])]),t._v("\n")])])]),a("p",[a("code",[t._v("User")]),t._v(", "),a("code",[t._v("Address")]),t._v(" 객체는 "),a("code",[t._v("Table")]),t._v(" 객체를 포함합니다."),a("br"),t._v("\n다음처럼 "),a("code",[t._v("__table__")]),t._v(" 속성을 통해 확인할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("__table__\nTable"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" MetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" nullable"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("False")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("length"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user_account"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" schema"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-객체-생성하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-객체-생성하기"}},[t._v("#")]),t._v(" ORM 객체 생성하기")]),t._v(" "),a("p",[t._v("위에서 정의한 뒤, 다음처럼 "),a("code",[t._v("ORM")]),t._v(" 객체를 생성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Cheeks"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sandy\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"데이터베이스에-적용하기-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#데이터베이스에-적용하기-2"}},[t._v("#")]),t._v(" 데이터베이스에 적용하기")]),t._v(" "),a("p",[t._v("이제 다음처럼 ORM으로 선언한 테이블을 실제로 데이터베이스에 적용되도록 할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" mapper_registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("create_all"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"기존-데이터베이스의-테이블을-orm-객체로-불러오기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#기존-데이터베이스의-테이블을-orm-객체로-불러오기"}},[t._v("#")]),t._v(" 기존 데이터베이스의 테이블을 ORM 객체로 불러오기")]),t._v(" "),a("p",[t._v("위의 모든 방법들은 테이블을 직접 선언하지않고, 데이터베이스에 테이블을 가져오는 방법이 있습니다."),a("br"),t._v("\n코드는 아래와 같습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_table "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" autoload_with"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nBEGIN "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("table_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("info"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("raw sql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nSELECT sql FROM "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("SELECT "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" FROM sqlite_master UNION ALL SELECT "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" FROM sqlite_temp_master"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" WHERE name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ? AND "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'table'")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("raw sql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some_table'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nPRAGMA main"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("foreign_key_list"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nPRAGMA main"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("index_list"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"some_table"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nROLLBACK\n")])])]),a("p",[t._v("이제 다음과 같이 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" some_table\nTable"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some_table'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" MetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'x'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INTEGER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("some_table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'y'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" INTEGER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("some_table"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n schema"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/26.a287ef6a.js b/assets/js/26.a287ef6a.js new file mode 100644 index 0000000..aebda0a --- /dev/null +++ b/assets/js/26.a287ef6a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{421:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"core와-orm-방식으로-행-조회하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#core와-orm-방식으로-행-조회하기"}},[t._v("#")]),t._v(" Core와 ORM 방식으로 행 조회하기")]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("이번 챕터에서는 SQLAlchemy에서 가장 자주 쓰이는 Select에 대해서 다룹니다.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"select-를-통한-sql-표현식-구성"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#select-를-통한-sql-표현식-구성"}},[t._v("#")]),t._v(" "),a("code",[t._v("select()")]),t._v(" 를 통한 SQL 표현식 구성")]),t._v(" "),a("p",[a("code",[t._v("select()")]),t._v(" 생성자는 "),a("code",[t._v("insert()")]),t._v(" 생성자와 같은 방식으로 쿼리문을 만들 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" select\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("p",[t._v("마찬가지로 쿼리문을 실행시키 위해 같은 레벨의 SQL 생성자들(select, insert, update, create등)처럼 "),a("code",[t._v("Connection.execute()")]),t._v(" 메서드에 쿼리를 넣어 실행시킬 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("한편 ORM을 사용해 "),a("code",[t._v("select")]),t._v(" 쿼리문을 실행시키고 싶을 때는 "),a("code",[t._v("Session.exeucte()")]),t._v("를 사용해야합니다.\n결과는 방금 전의 예제와 마찬가지로 "),a("code",[t._v("Row")]),t._v("객체를 반환하지만 이 객체는 이전의 튜토리얼, "),a("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/blob/main/tutorial/4.%20%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%20%EB%A9%94%ED%83%80%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A1%9C%20%EC%9E%91%EC%97%85%ED%95%98%EA%B8%B0.md#%ED%85%8C%EC%9D%B4%EB%B8%94%EC%97%90-%EB%A7%A4%ED%95%91%ED%95%A0-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%EC%96%B8",target:"_blank",rel:"noopener noreferrer"}},[t._v("4. 데이터베이스 메타데이터로 작업하기"),a("OutboundLink")],1),t._v("에서\n정의했던 "),a("code",[t._v("User")]),t._v("객체를 포함하고 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# User 객체의 인스턴스 안에 있는 각 row 들을 출력")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"from절과-컬럼-세팅하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#from절과-컬럼-세팅하기"}},[t._v("#")]),t._v(" FROM절과 컬럼 세팅하기")]),t._v(" "),a("p",[a("code",[t._v("select()")]),t._v("함수는 위치인자로 "),a("code",[t._v("Column")]),t._v("이나 "),a("code",[t._v("Table")]),t._v("등을 포함한 다양한 객체들을 받을 수 있습니다.\n이러한 인자 값들은 "),a("code",[t._v("select()")]),t._v("함수의 반환 값, 즉 SQL쿼리문으로 표현 될 수있고 "),a("code",[t._v("FROM")]),t._v("절을 세팅해주기도 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("각각의 컬럼들을 "),a("code",[t._v("Core")]),t._v("를 이용해 조회하려면 "),a("code",[t._v("Table.c")]),t._v("접근자를 통해 "),a("code",[t._v("Column")]),t._v("객체에 접근하면 됩니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-엔터티-및-열-조회"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-엔터티-및-열-조회"}},[t._v("#")]),t._v(" ORM 엔터티 및 열 조회")]),t._v(" "),a("p",[t._v("SQL 쿼리를 SqlAlchemy에서 구현할 때 테이블이나 컬럼을 표현하기 위해 "),a("code",[t._v("User")]),t._v("객체같은 ORM 엔터티나, "),a("code",[t._v("User.name")]),t._v("과 같이 컬럼이 매핑된 속성(어트리뷰트)을 사용할 수 있습니다.\n아래의 예제는 "),a("code",[t._v("User")]),t._v("엔터티를 조회하는 예제이지만 사실은\n"),a("code",[t._v("user_table")]),t._v(" 를 사용했을 때와 결과가 동일합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("위의 예제의 쿼리를 ORM "),a("code",[t._v("Session.exeucte()")]),t._v("를 통해 똑같이 실행 할 수 있는데, 이때는 "),a("code",[t._v("User")]),t._v("엔터티를 조회하는 것과 "),a("code",[t._v("user_info")]),t._v("를 조회하는 것에 차이가 있습니다.\n"),a("code",[t._v("user_info")]),t._v("를 조회하든 "),a("code",[t._v("User")]),t._v("엔티티를 조회 하든 둘 다"),a("code",[t._v("Row")]),t._v("객체가 반환되지만 "),a("code",[t._v("User")]),t._v("엔터티를 조회 할 경우에는\n"),a("code",[t._v("User")]),t._v("인스턴스를 포함한 "),a("code",[t._v("Row")]),t._v(" 객체가 반환됩니다.")]),t._v(" "),a("blockquote",[a("p",[t._v("여기서 "),a("code",[t._v("user_table")]),t._v("과 "),a("code",[t._v("User")]),t._v("는 "),a("a",{attrs:{href:""}},[t._v("이전 챕터")]),t._v("에서 만들어졌는데,\n"),a("code",[t._v("user_table")]),t._v("은 "),a("code",[t._v("Table")]),t._v(" 객체이고\n"),a("code",[t._v("User")]),t._v("는 "),a("code",[t._v("Base")]),t._v(" 객체를 상속받아"),a("code",[t._v("Table")]),t._v("객체를 포함하고 있는 엔터티입니다.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("한편 객체 속성(class-bound attributes)을 사용해 원하는 컬럼들을 조회할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("객체 속성을 "),a("code",[t._v("Session.execute()")]),t._v("을 이용해 조회 할 경우에는\n인자로 보내진 객체 속성의 값(컬럼 값)이 아래와 같이 반환됩니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\trow "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\t"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("이러한 방법들은 믹스인 방법으로 섞어서 사용할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"라벨링된-sql-표현식-조회하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#라벨링된-sql-표현식-조회하기"}},[t._v("#")]),t._v(" 라벨링된 SQL 표현식 조회하기")]),t._v(" "),a("p",[a("code",[t._v("SELECT name AS username FROM user_account")]),t._v(" 쿼리를 실행 할 경우 아래와 같은 결과가 나옵니다.")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[t._v("username")])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("patrick")])]),t._v(" "),a("tr",[a("td",[t._v("sandy")])]),t._v(" "),a("tr",[a("td",[t._v("spongebob")])])])]),t._v(" "),a("p",[t._v("여기서 우리는 "),a("code",[t._v("name")]),t._v("컬럼의 이름을 "),a("code",[t._v("username")]),t._v("으로 라벨링 해줬기 때문에 상단 컬럼에 "),a("code",[t._v("username")]),t._v(" 이 뜨는 건데요.\n이러한 기능을 SQLAlchemy의 "),a("code",[t._v("ColumnElement.label()")]),t._v("함수를 이용해 동일하게 구현할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cast\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Username: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"username"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 이렇게 라벨링 합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("username"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 라벨링한 부분은 이렇게 접근할 수 있습니다.")]),t._v("\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" patrick\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" sandy\nUsername"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" spongebob\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"문자열-컬럼-조회하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#문자열-컬럼-조회하기"}},[t._v("#")]),t._v(" 문자열 컬럼 조회하기")]),t._v(" "),a("p",[t._v("보통 "),a("code",[t._v("Select")]),t._v("객체나 "),a("code",[t._v("select()")]),t._v(" 생성자를 이용 해 컬럼을 조회하는 경우가 많지만 가끔은 임의로 문자열과 함께 컬럼을 조회 해야하는 경우가 있습니다. 이번 섹션에서는 이러한 스트링 데이터를 조회 하는 방법에 다룹니다.")]),t._v(" "),a("p",[a("code",[t._v("text()")]),t._v(" 생성자는 이전 챕터 "),a("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/blob/main/tutorial/3.%20%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%20%EB%B0%8F%20DBAPI%20%EC%9E%91%EC%97%85.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("3. 트랜잭션 및 데이터베이스API 작업"),a("OutboundLink")],1),t._v("에서 한 번 소개가 되었는데요, 이 "),a("code",[t._v("text()")]),t._v("생성자안에 "),a("code",[t._v("SELECT")]),t._v("구문을 곧바로 넣어 사용할 수도 있었습니다.")]),t._v(" "),a("p",[t._v("한편 우리는 "),a("code",[t._v("SELECT 'some_phrase', name FROM user_account")]),t._v(" 와 같은 쿼리를 실행시키고 싶다고 생각해봅시다.\n이 때, "),a("code",[t._v("some_phrase")]),t._v("은 문자열이기 때문에 꼭 큰 따옴표나 작은 따옴표로 감싸줘야합니다. 그리고 그 결과, 출력물에도 어쩔 수 없이 작은 따옴표가 전부 붙어서 나옵니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" text\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" text"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"'some phrase'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'some phrase'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("그래서 보통은 "),a("code",[t._v("text()")]),t._v("보다 "),a("code",[t._v("literal_column()")]),t._v("을 사용해 작은 따옴표가 결과물에 붙어져서 나오는 문제를 해결할 수 있습니다."),a("br"),t._v("\n여기에서 "),a("code",[t._v("text")]),t._v("와 "),a("code",[t._v("literal_column()")]),t._v("은 거의 비슷하지만 "),a("code",[t._v("literal_column()")]),t._v("은 명시적으로 컬럼을 의미하고, 서브쿼리나 다른 SQL 표현식에서 쓰일 수 있게 라벨링도 할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" literal_column\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" literal_column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"'some phrase'\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"p"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(", ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" patrick\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sandy\nsome phrase"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" spongebob\n\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"where절"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#where절"}},[t._v("#")]),t._v(" WHERE절")]),t._v(" "),a("p",[t._v("SQLAlchemy를 사용하면 Python 연산자를 사용하여 "),a("code",[t._v("name")]),t._v(" = 'thead'"),a("code",[t._v("또는")]),t._v("user_id > 10` 인 데이터만 출력하는 쿼리를 쉽게 작성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nuser_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("name_1\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("user_id_1\n")])])]),a("p",[a("code",[t._v("WHERE")]),t._v("절을 만들기 위해 "),a("code",[t._v("Select.where()")]),t._v("메서드안에 인자값을 넣어 사용할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("p",[t._v("WHERE 절을 통한 JOIN을 구현해야 할 때, 아래와 같이 작성 가능합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE user_account.name = :name_1 AND address.user_id = user_account.id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 위와 같은 표현이지만, 아래처럼 where()메서드의 파라미터로 넘기는 방식도 가능합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE user_account.name = :name_1 AND address.user_id = user_account.id\n"""')]),t._v("\n")])])]),a("p",[a("code",[t._v("and_()")]),t._v(", "),a("code",[t._v("or_()")]),t._v("등의 연결 구문도 구현가능합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" or_\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" or_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM address, user_account\nWHERE (user_account.name = :name_1 OR user_account.name = :name_2)\nAND address.user_id = user_account.id\n"""')]),t._v("\n")])])]),a("p",[t._v("단순히 같은지, 아닌지 비교하는 경우(equality) "),a("code",[t._v("Select.filter_by()")]),t._v("도 자주 사용됩니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("filter_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = :name_1 AND user_account.fullname = :fullname_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"from절과-join-명시하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#from절과-join-명시하기"}},[t._v("#")]),t._v(" FROM절과 JOIN 명시하기")]),t._v(" "),a("p",[t._v("앞에서 언급했지만 "),a("code",[t._v("FROM")]),t._v("절은 따로 명시하지 않아도 "),a("code",[t._v("select()")]),t._v("메서드의 인자에 넣은 컬럼들로 자동 세팅이 됩니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 따로 FROM 절을 명시하지 않았지만 FROM 절이 세팅되어 출력됩니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("만약 "),a("code",[t._v("select()")]),t._v("의 위치 인자로 서로 다른 두 개의 테이블을 참조하는 컬럼을"),a("code",[t._v(",")]),t._v("(컴마)로 구분지어 넣을 수도 있습니다")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account, address\n"""')]),t._v("\n")])])]),a("p",[t._v("서로 다른 두 개의 테이블을 "),a("code",[t._v("JOIN")]),t._v("조인하고 싶다면, 이용할 수 있는 메서드가 두 가지가 있는데요,\n하나는 "),a("code",[t._v("Select.join()")]),t._v("메서드로 명시적으로 "),a("code",[t._v("JOIN")]),t._v(" 할 왼쪽에 들어갈 테이블, 오른쪽에 들어 갈 테이블을 직접 지정할 수 있습니다")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("다른 하나는 "),a("code",[t._v("Select.join()")]),t._v("메서드로 오른쪽에 들어갈 테이블만 명시적으로 적어주고\n나머지 테이블은 암시적으로 컬럼을 선택할 때 참조하게 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 위와 동일한 표현이지만, 조인할 왼쪽 테이블(user_table)은 암시적으로 표현됩니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[t._v("또는 "),a("code",[t._v("JOIN")]),t._v(" 하는 두 개의 테이블을 조금 더 명시적으로 작성하고 싶거나 "),a("code",[t._v("FROM")]),t._v("절에 명시적인 추가 옵션을 주고 싶다면\n아래와 같이 작성 할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[a("code",[t._v("Select.select_from()")]),t._v("을 사용하는 또 다른 경우는 우리가 조회하고 싶은 컬럼들을 통해 암시적으로 "),a("code",[t._v("FROM")]),t._v(" 절을 세팅할 수 없는 경우입니다. 예를 들면 일반적인 SQL 쿼리문에서 "),a("code",[t._v("count(*)")]),t._v("를 조회하기 위해선 SQLAlchemy의 "),a("code",[t._v("sqlalchemy.sql.expression.func")]),t._v("를 사용해야합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'*'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(:count_2) AS count_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"on절-세팅하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#on절-세팅하기"}},[t._v("#")]),t._v(" On절 세팅하기")]),t._v(" "),a("p",[t._v("그런데 뭔가 이상한게 있었죠?\n사실 이 전의 예제에서 "),a("code",[t._v("Select.select_from()")]),t._v("이나 "),a("code",[t._v("select.join()")]),t._v("을 이용해 두 테이블을 "),a("code",[t._v("JOIN")]),t._v("할 때 암시적으로 "),a("code",[t._v("ON")]),t._v("절이 세팅되었답니다."),a("br"),t._v("\n왜 자동으로 "),a("code",[t._v("ON")]),t._v(" 절이 세팅 됐냐면, "),a("code",[t._v("user_table")]),t._v("객체와, "),a("code",[t._v("address_table")]),t._v(" 객체가 "),a("code",[t._v("ForeignKeyConstraint")]),t._v(", 즉 외부키 제약을 갖고 있어서 자동으로 세팅이 된 것입니다.")]),t._v(" "),a("p",[t._v("만약에 "),a("code",[t._v("Join")]),t._v("의 대상인 두 개의 테이블에서 이러한 제약 key가 없을 경우 "),a("code",[t._v("ON")]),t._v("절을 직접 지정해야 합니다. 이러한 기능은 "),a("code",[t._v("Select.join()")]),t._v("나 "),a("code",[t._v("Select.join_from()")]),t._v("메서드에 파라미터 전달을 통해 명시적으로 "),a("code",[t._v("ON")]),t._v("절을 세팅할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.email_address\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"outer-full-join"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#outer-full-join"}},[t._v("#")]),t._v(" OUTER, FULL Join")]),t._v(" "),a("p",[t._v("SQLAlchemy에서 "),a("code",[t._v("LEFT OUTER JOIN")]),t._v(", "),a("code",[t._v("FULL OUTER JOIN")]),t._v("를 구현하려면\n"),a("code",[t._v("Select.join()")]),t._v("과 "),a("code",[t._v("Select.join_from()")]),t._v("메서드의 키워드 인자로 "),a("code",[t._v("Select.join.isouter")]),t._v(",\n"),a("code",[t._v("Select.join.full")]),t._v("를 사용할 수 있습니다.")]),t._v(" "),a("p",[a("code",[t._v("LEFT OUTER JOIN")]),t._v("을 구현 한 경우,")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" isouter"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account LEFT OUTER JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("p",[a("code",[t._v("FULL OUTER JOIN")]),t._v("을 구현 한 경우,")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" full"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account FULL OUTER JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"order-by-group-by-having"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#order-by-group-by-having"}},[t._v("#")]),t._v(" ORDER BY, GROUP BY, HAVING")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("ORDER BY")]),t._v("절은 "),a("code",[t._v("SELECT")]),t._v("절에서 조회한 행들의 순서를 설정할 수 있습니다.")]),t._v(" "),a("li",[a("code",[t._v("GROUP BY")]),t._v("절은 그룹 함수로 조회된 행들을 특정한 컬럼을 기준으로 그룹을 만듭니다.")]),t._v(" "),a("li",[a("code",[t._v("HAVING")]),t._v("은 "),a("code",[t._v("GROUP BY")]),t._v("절을 통해 생성된 그룹에 대해 조건을 겁니다.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"order-by"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#order-by"}},[t._v("#")]),t._v(" ORDER BY")]),t._v(" "),a("p",[a("code",[t._v("Select.order_by()")]),t._v("를 이용해 "),a("code",[t._v("ORDER BY")]),t._v("기능을 구현할 수 있습니다. 이때 위치 인자 값으로 "),a("code",[t._v("Column")]),t._v("객체나 이와 비슷한 객체들을 받을 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account ORDER BY user_account.name\n"""')]),t._v("\n")])])]),a("p",[t._v("오름차순, 내림차순은\n"),a("code",[t._v("ColumnElement.asc()")]),t._v(", "),a("code",[t._v("ColumnElement.desc()")]),t._v(" 제한자를 통해 구현 할 수 있습니다.\n아래 예제는 "),a("code",[t._v("user_account.fullname")]),t._v("컬럼 기준으로 내림 차순으로 정렬합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("desc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account ORDER BY user_account.fullname DESC\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"그룹함수-group-by-having"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#그룹함수-group-by-having"}},[t._v("#")]),t._v(" 그룹함수 : GROUP BY, Having")]),t._v(" "),a("p",[t._v("SQL에서는 집계함수를 이용해 조회 된 여러개의 행들을 하나의 행으로 합칠 수도 있습니다.\n집계함수의 예로 "),a("code",[t._v("COUNT()")]),t._v(", "),a("code",[t._v("SUM()")]),t._v(", "),a("code",[t._v("AVG()")]),t._v("등이 있습니다.")]),t._v(" "),a("p",[t._v("SQLAlchemy에서는 "),a("code",[t._v("func")]),t._v("라는 네임스페이스를 이용해 SQL함수를 제공하는데, 이 "),a("code",[t._v("func")]),t._v("는\nSQL함수의 이름이 주어지면 "),a("code",[t._v("Function")]),t._v("인스턴스를 생성합니다.")]),t._v(" "),a("p",[t._v("아래의 예제에서는 "),a("code",[t._v("user_account.id")]),t._v("컬럼을 SQL "),a("code",[t._v("COUNT()")]),t._v("함수에 렌더링 하기 위해 "),a("code",[t._v("count()")]),t._v("함수를 호출합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" count_fn "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("count_fn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\ncount(user_account.id)\n"""')]),t._v("\n")])])]),a("p",[t._v("SQL 함수에 관해서는 "),a("a",{attrs:{href:""}},[t._v("SQL 함수 다루기")]),t._v("에서 더 자세히 설명되어 있습니다.")]),t._v(" "),a("p",[t._v("다시 설명하자면")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("GROUP BY")]),t._v("는 조회된 행들을 특정 그룹으로 나눌 때 필요한 함수입니다.\n만약에 "),a("code",[t._v("SELECT")]),t._v(" 절에서 몇 개의 컬럼을 조회 할 경우 SQL에서는 직,간접적으로 이 컬럼들이 기본키(primary key)를 기준으로\n"),a("code",[t._v("GROUP BY")]),t._v("에 종속되도록 합니다.")]),t._v(" "),a("li",[a("code",[t._v("HAVING")]),t._v(" 는 "),a("code",[t._v("GROUP BY")]),t._v("로 만들어진 그룹들에 대해 조건을 적용 할 경우 필요합니다.(그룹에 대해 조건을 걸기 때문에 "),a("code",[t._v("WHERE")]),t._v("절과 비슷합니다)")])]),t._v(" "),a("p",[t._v("SQLAlchemy에서는 "),a("code",[t._v("Select.group_by()")]),t._v("와 "),a("code",[t._v("Select.having()")]),t._v("를 이용해 "),a("code",[t._v("GROUP BY")]),t._v("와 "),a("code",[t._v("HAVING")]),t._v("을 구현 할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" having"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('""" 위 구문은 아래 SQL을 표현합니다.\nSELECT user_account.name, count(address.id) AS count\nFROM user_account JOIN address ON user_account.id = address.user_id GROUP BY user_account.name\nHAVING count(address.id) > ?\n[...] (1,)\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"별칭을-통해-그룹화-또는-순서-정렬하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#별칭을-통해-그룹화-또는-순서-정렬하기"}},[t._v("#")]),t._v(" 별칭을 통해 그룹화 또는 순서 정렬하기")]),t._v(" "),a("p",[t._v("어떤 데이터 베이스 백엔드에서는 집계함수를 사용해 테이블을 조회 할 때 "),a("code",[t._v("ORDER BY")]),t._v(" 절이나 "),a("code",[t._v("GROUP BY")]),t._v("절에 이미 명시된 집계함수를 "),a("strong",[t._v("다시")]),t._v(" 명시적으로 사용하지 않는 것이 중요합니다.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# NOT GOOD")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("COUNT")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("GROUP")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# CORRECT")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("COUNT")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" cnt_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("GROUP")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ORDER")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("BY")]),t._v(" cnt_id\n")])])]),a("p",[t._v("따라서 별칭을 통해 "),a("code",[t._v("ORDER BY")]),t._v(" 나 "),a("code",[t._v("GROUP BY")]),t._v("를 구현하려면\n"),a("code",[t._v("Select.order_by()")]),t._v(" 또는 "),a("code",[t._v("Select.group_by()")]),t._v("메서드에 인자로 사용 할 별칭을 넣어주면 됩니다."),a("br"),t._v("\n여기에 사용된 별칭이 먼저 렌더링 되는건 아니고 컬럼절에 사용된 별칭이 먼저 렌더링 됩니다. 그리고 렌더링된 별칭이 나머지 쿼리문에서 매칭되는게 없다면 에러가 발생합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" desc\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 컬럼에도 num_addresses 별칭이 들어가고 order_by에도 같은 별칭이 들어갑니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'num_addresses'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\\\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" desc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"num_addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT address.user_id, count(address.id) AS num_addresses\nFROM address GROUP BY address.user_id ORDER BY address.user_id, num_addresses DESC\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"별칭-사용하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#별칭-사용하기"}},[t._v("#")]),t._v(" 별칭 사용하기")]),t._v(" "),a("p",[t._v("여러개의 테이블을 "),a("code",[t._v("JOIN")]),t._v("을 이용해 조회 할 경우 쿼리문에서 테이블 이름을 여러번 적어줘야 하는 경우가 많습니다.\nSQL에서는 이러한 문제를 테이블 명이나 서브 쿼리에 별칭(aliases)를 지어 반복되는 부분을 줄일 수 있습니다.")]),t._v(" "),a("p",[t._v("한편 SQLAlchemy에서는 이러한 별칭들은 Core의 "),a("code",[t._v("FromCaluse.alias()")]),t._v("함수를 이용해 구현 할 수 있습니다.\n"),a("code",[t._v("Table")]),t._v("객체 네임스페이스 안에 "),a("code",[t._v("Column")]),t._v("객체가 있어 "),a("code",[t._v("Table.c")]),t._v("로 컬럼명에 접근할 수 있었는데요.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[a("code",[t._v("Alias")]),t._v("객체 네임스페이스 안에도 "),a("code",[t._v("Column")]),t._v("객체가 있어 "),a("code",[t._v("Alias.c")]),t._v("로 컬럼에 접근 가능합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# user_alias_1과 user_alias_2 모두 Alias객체입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("‘table1’"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("‘table2’"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 방금 만든 테이블 별명으로 컬럼에 접근하려면 Alias.c.컬럼명으로 접근해야합니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT table1.name, table2.name AS name_1 \nFROM user_account AS table1 JOIN user_account AS table2 ON table1.id > table2.id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-엔티티-별칭"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-엔티티-별칭"}},[t._v("#")]),t._v(" ORM 엔티티 별칭")]),t._v(" "),a("p",[t._v("ORM도 "),a("code",[t._v("FromClause.alias()")]),t._v("메서드와 비슷한 "),a("code",[t._v("aliased()")]),t._v("함수가 존재합니다.")]),t._v(" "),a("p",[t._v("이 ORM "),a("code",[t._v("aliased()")]),t._v("는 ORM의 기능을 유지하면서 원래 매핑된 "),a("code",[t._v("Table")]),t._v("객체에 내부적으로 "),a("code",[t._v("Alias")]),t._v("객체를 생성합니다.")]),t._v(" "),a("blockquote",[a("p",[t._v("여기서 "),a("code",[t._v("Address")]),t._v("와 "),a("code",[t._v("User")]),t._v("객체는 "),a("a",{attrs:{href:""}},[t._v("이전 챕터")]),t._v("에서 만들어졌는데,\n두 객체 모두 "),a("code",[t._v("Base")]),t._v(" 객체를 상속받아"),a("code",[t._v("Table")]),t._v("객체를 포함하고 있는 엔터티입니다.")])]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" user_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("alias"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 예제에서는 User나 Address엔터티에 적용됩니다. ")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname \nFROM user_account JOIN address AS address_1 ON user_account.id = address_1.user_id JOIN address AS address_2 ON user\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"서브쿼리와-cte"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#서브쿼리와-cte"}},[t._v("#")]),t._v(" 서브쿼리와 CTE")]),t._v(" "),a("p",[t._v("이 섹션에서는 일반적으로 SELECT의 FROM 절에 있는 서브 쿼리에 대해 설명합니다. 서브쿼리와 유사한 방식으로 사용되지만 추가 기능이 포함된 CTE도 다룹니다.")]),t._v(" "),a("blockquote",[a("p",[t._v("CTE(Common Table Expression)는 동일 쿼리 내에서 여러번 참조할 수 있게 하는 쿼리 내 임시 결과 집합입니다. "),a("a",{attrs:{href:"https://blog.sengwoolee.dev/84",target:"_blank",rel:"noopener noreferrer"}},[t._v("이 글"),a("OutboundLink")],1),t._v("에 CTE에 대해 잘 설명되어 있으니, 잘 모르시겠는 분들은 참고하시면 좋습니다.")])]),t._v(" "),a("p",[t._v("SQLAlchemy는 "),a("code",[t._v("Subquery")]),t._v(" 개체를\n"),a("code",[t._v("Select.subquery()")]),t._v("사용하여 서브 쿼리를 나타내고 "),a("code",[t._v("Select.cte()")]),t._v(" 를 사용하여 CTE를 나타냅니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(address.id) AS count, address.user_id\nFROM address GROUP BY address.user_id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ON절은 두 개의 테이블이 이미 foreigh key로 제약이 걸려있어 자동 바인딩된다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, user_account.fullname, anon_1.count\nFROM user_account JOIN (SELECT count(address.id) AS count, address.user_id AS user_id\nFROM address GROUP BY address.user_id) AS anon_1 ON user_account.id = anon_1.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"계층-쿼리"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#계층-쿼리"}},[t._v("#")]),t._v(" 계층 쿼리")]),t._v(" "),a("p",[t._v("SQLAlchemy에서 CTE 구문을 사용하는 방법은 서브 쿼리 구문이 사용되는 방식과 거의 동일합니다. 대신 "),a("code",[t._v("Select.subquery()")]),t._v(" 메서드의 호출을 "),a("code",[t._v("Select.cte()")]),t._v("를 사용하도록 변경하여 결과 객체를 FROM 요소로 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nWITH anon_1 AS\n(SELECT count(address.id) AS count, address.user_id AS user_id\nFROM address GROUP BY address.user_id)\n SELECT user_account.name, user_account.fullname, anon_1.count\nFROM user_account JOIN anon_1 ON user_account.id = anon_1.user_id\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"orm-엔티티-서브쿼리-cte"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-엔티티-서브쿼리-cte"}},[t._v("#")]),t._v(" ORM 엔티티 서브쿼리, CTE")]),t._v(" "),a("p",[t._v("여기서는 "),a("code",[t._v("aliased()")]),t._v("가 "),a("code",[t._v("Subquery")]),t._v(", "),a("code",[t._v("CTE")]),t._v("서브 쿼리에 대해 동일한 작업을 수행하는 과정을 확인할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("like"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'%@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('""" 위 구문은 아래 쿼리를 표현합니다.\nSELECT user_account.id, user_account.name, user_account.fullname,\nanon_1.id AS id_1, anon_1.email_address, anon_1.user_id\nFROM user_account JOIN\n(SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id\nFROM address\nWHERE address.email_address NOT LIKE ?) AS anon_1 ON user_account.id = anon_1.user_id\nORDER BY user_account.id, anon_1.id\n[...] (\'%@aol.com\',)\n"""')]),t._v("\n\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("아래는 CTE생성자를 이용해 위와 같은 사용하는 예제입니다")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" cte "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("like"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'%@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" address_cte "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_cte"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"스칼라-서브-쿼리-상호연관-쿼리"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#스칼라-서브-쿼리-상호연관-쿼리"}},[t._v("#")]),t._v(" 스칼라 서브 쿼리, 상호연관 쿼리")]),t._v(" "),a("p",[t._v("스칼라 서브 쿼리에 대해 설명하기전 잠시 SQL에서 서브 쿼리에 대해 이야기 하겠습니다. "),a("a",{attrs:{href:"https://rinuas.tistory.com/entry/%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%ACSub-Query",target:"_blank",rel:"noopener noreferrer"}},[t._v("출처:바이헨 블로그"),a("OutboundLink")],1)]),t._v(" "),a("ul",[a("li",[t._v('"서브쿼리"란 하나의 SQL문에 속한 '),a("code",[t._v("SELECT")]),t._v('문을 말하고 서브 쿼리의 바깥 쪽에 있는 SQL문을 "메인 쿼리"라고 합니다.')])]),t._v(" "),a("p",[t._v("이때 서브쿼리의 종류는 메인 쿼리 컬럼을 참조 여부, 서브쿼리의 선언 위치, 서브 쿼리 실행 결과 ROW수에 따라 종류가 나눠집니다")]),t._v(" "),a("ul",[a("li",[t._v("메인 쿼리 컬럼 참조 여부에 따른 구분\n"),a("ul",[a("li",[a("strong",[t._v("상호 연관 서브쿼리")]),t._v(" : 서브쿼리가 메인 쿼리 컬럼을 참조")]),t._v(" "),a("li",[t._v("비상호 연관 서브 쿼리: 서브쿼리가 메인 쿼리의 컬럼을 참조하지 않고 독립적으로 수행하고 메인쿼리에 정보를 전달할 목적으로 사용됩니다.")])])]),t._v(" "),a("li",[t._v("서브쿼리 선언 위치에 따른 구분\n"),a("ul",[a("li",[a("strong",[t._v("스칼라 서브 쿼리")]),t._v(" : SELECT 문의 컬럼자리에 오는 서브 쿼리(상호 연관 서브쿼리)")]),t._v(" "),a("li",[t._v("인라인 뷰 : FROM절 자리에 오는 서브 쿼리 (상호 연관 서브 쿼리)")]),t._v(" "),a("li",[t._v("중첩 서브 쿼리 : Where절 자리에 오는 서브 쿼리 (비상호 연관 서브 쿼리)")])])]),t._v(" "),a("li",[t._v("서브 쿼리 실행 결과 ROW수에 따른 구분\n"),a("ul",[a("li",[t._v("단일행 서브쿼리(서브 쿼리 연산결과 ROW1개)")]),t._v(" "),a("li",[t._v("단중행 서브쿼리(서브 쿼리 연산결과 ROW2개이상):IN, ANY, ALL, EXSITS")])])])]),t._v(" "),a("br"),t._v(" "),a("p",[t._v("SQLAlchemy에서 스칼라 서브 쿼리는 "),a("code",[t._v("ColumnElement")]),t._v("객체의 일부인 "),a("code",[t._v("ScalarSelect")]),t._v("를 사용하는 방면 일반 서브 쿼리는"),a("code",[t._v("FromClause")]),t._v("객체에 있는 "),a("code",[t._v("Subquery")]),t._v("를 사용합니다.")]),t._v(" "),a("p",[t._v("스칼라 서브쿼리는 앞에서 설명했던 "),a("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/blob/feature/tutorial/5.%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%ED%95%B8%EB%93%A4%EB%A7%81%ED%95%98%EA%B8%B0%20-%20Select%EA%B5%AC%EB%AC%B8.md#%EA%B7%B8%EB%A3%B9%ED%95%A8%EC%88%98--group-by-having",target:"_blank",rel:"noopener noreferrer"}},[t._v("그룹 합수"),a("OutboundLink")],1),t._v("와 같이 쓰이고는 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Select.scalar_subquery()를 이용해 구현한 스칼라 서브 쿼리")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" scalar_subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#ScalarSelect객체")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\n(SELECT count(address.id) AS count_1\nFROM address, user_account\nWHERE user_account.id = address.user_id)\n"""')]),t._v("\n")])])]),a("p",[t._v("스칼라 서브 쿼리가 "),a("code",[t._v("user_account")]),t._v("와 "),a("code",[t._v("address")]),t._v("를 FROM절에서 렌더링하지만\n메인쿼리에 있는 "),a("code",[t._v("user_account")]),t._v("테이블이 있어서\n스칼라 서브 쿼리에서는 "),a("code",[t._v("user_account")]),t._v(" 테이블을 렌더링하지 않습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("label"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"address_count"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.name, (SELECT count(address.id) AS count_1\nFROM address\nWHERE user_account.id = address.user_id) AS address_count\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("한편 상호 연관 쿼리를 작성 할 때 테이블 간의 연결이 모호해질 수도 있습니다.")]),t._v(" "),a("blockquote",[a("p",[t._v("튜토리얼에 나와있는 상호 연관쿼리 예제는 제가 이해하지 못했습니다.\n잘 아시는분은 이문서에 기여 부탁드립니다.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"union-union-all-연산자들"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#union-union-all-연산자들"}},[t._v("#")]),t._v(" UNION, UNION ALL 연산자들")]),t._v(" "),a("p",[t._v("SQL에서는 "),a("code",[t._v("UNION")]),t._v(", "),a("code",[t._v("UNION ALL")]),t._v("등으로 두 개의 "),a("code",[t._v("SELECT")]),t._v("문을 합치는 것을 의미합니다."),a("br"),t._v("\n아래와 같이 쿼리문을 실행 할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("union")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("SELECT")]),t._v(" email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" address\n")])])]),a("p",[t._v("그 외에도 집합 연산인 "),a("code",[t._v("INTERSECT")]),t._v("(교집합), "),a("code",[t._v("EXCEPT")]),t._v("(차집합)도 SQL에서 지원합니다."),a("br"),t._v("\nSQLAlchemy에서 "),a("code",[t._v("Select")]),t._v(" 객체에 대하여 "),a("code",[t._v("union()")]),t._v(", "),a("code",[t._v("intersect()")]),t._v(", "),a("code",[t._v("except_()")]),t._v(" 혹은\n"),a("code",[t._v("union_all()")]),t._v(", "),a("code",[t._v("intersect_all()")]),t._v(", "),a("code",[t._v("except_all()")]),t._v("을 지원합니다.")]),t._v(" "),a("p",[t._v("이러한 함수들의 반환 값은 "),a("code",[t._v("CompoundSelect")]),t._v("인데 "),a("code",[t._v("Select")]),t._v("와 비슷하게 쓰일 수 있는 객체이지만 더 적은 메서드를 갖고 있습니다."),a("br"),t._v(" "),a("code",[t._v("union_all()")]),t._v("의 반환값 "),a("code",[t._v("CompoundSelect")]),t._v("객체는 "),a("code",[t._v("Connection.execute()")]),t._v("로 실행될 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" union_all\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" union_all"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stmt2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#u는 CompoundSelect 객체입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[a("code",[t._v("Subquery")]),t._v("객체를 만들기 위해 "),a("code",[t._v("Select")]),t._v("가 "),a("code",[t._v("SelectBase.subquery()")]),t._v("메서드를 제공하는 것처럼\n"),a("code",[t._v("CompoundSelect")]),t._v("객체를 서브 쿼리로 비슷한 방식으로 사용 할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" u_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" u"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("u_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"exists-서브쿼리들"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exists-서브쿼리들"}},[t._v("#")]),t._v(" EXISTS 서브쿼리들")]),t._v(" "),a("p",[t._v("SQLAlchemy는 "),a("code",[t._v("SelectBase.exists()")]),t._v("메서드를 통해 "),a("code",[t._v("Exists")]),t._v("객체를 만들어 "),a("code",[t._v("EXISTS")]),t._v(" 구문을 구현합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# subq는 Exists객체입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" group_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" having"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exists"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nEXISTS (SELECT count(address.id) AS count_1 \nFROM address, user_account \nWHERE user_account.id = address.user_id GROUP BY address.user_id \nHAVING count(address.id) > :count_2)\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[t._v("한편 "),a("code",[t._v("EXISTS")]),t._v(" 구문은 부정으로 사용되지 않는 경우가 더 많습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 이메일 주소가 없는 유저네임을 선택하는 쿼리문입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# "~" 연산이 들어간 부분을 확인해보세요')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exists"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("~")]),t._v("subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT user_account.id \nFROM user_account \nWHERE NOT (EXISTS (SELECT count(address.id) AS count_1 \nFROM address \nWHERE user_account.id = address.user_id GROUP BY address.user_id \nHAVING count(address.id) > :count_2))\n"""')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"sql-함수-다뤄보기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#sql-함수-다뤄보기"}},[t._v("#")]),t._v(" SQL 함수 다뤄보기")]),t._v(" "),a("p",[t._v("이 섹션 앞부분의 "),a("a",{attrs:{href:""}},[t._v("그룹함수 :GROUP BY, HAVING")]),t._v("에서 처음 소개된 "),a("code",[t._v("func")]),t._v(" 객체는\n새로운 "),a("code",[t._v("Function")]),t._v(" 객체를 생성하기 위한 팩토리 역할을 합니다."),a("br"),t._v(" "),a("code",[t._v("select()")]),t._v("와 같은 구문을 사용 할때는 인자 값으로 "),a("code",[t._v("func")]),t._v("객체로 생성된 SQL함수를 받을 수 있습니다.")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("count()")]),t._v(" : 집계함수로 행의 개수를 출력하는데 사용됩니다."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# cnt는 타입입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" cnt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("cnt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(*) AS count_1FROM user_account\n"""')]),t._v("\n")])])])]),t._v(" "),a("li",[a("code",[t._v("lower()")]),t._v(" : 문자열 함수로 문자열을 소문자로 바꿔줍니다."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("lower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"A String With Much UPPERCASE"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT lower(:lower_2) AS lower_1\n"""')]),t._v("\n")])])])]),t._v(" "),a("li",[a("code",[t._v("now()")]),t._v(" : 현재 시간과 날짜를 반환해주는 함수입니다.\n이 함수는 굉장히 흔하게 사용되는 함수이기에 SQLAlchemy는 서로 다른 백엔드에서 손쉽게 렌더링 할 수 있도록 도와줍니다."),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("datetime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("datetime"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])])]),t._v(" "),a("p",[t._v("다양한 데이터베이스 백엔드에서는 서로 다른 이름의 SQL함수를 갖고 있습니다."),a("br"),t._v("\n따라서 "),a("code",[t._v("func")]),t._v(" 는 가능한 자유롭게 어떤 이름이든 "),a("code",[t._v("func")]),t._v("의 네임스페이스에 접근 할 수 있도록 허용합니다. 그리고 그 이름을 자동으로 SQL 함수로 받아들여 렌더링 합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# crazy_function의 데이터 타입은 Function입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" crazy_function "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("some_crazy_function"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("17")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("crazy_function"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT some_crazy_function(user_account.name, :some_crazy_function_2) AS some_crazy_function_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("p",[t._v("한편 SQLAlchemy에서는 SQL에서 일반적으로 자주 쓰이는 "),a("code",[t._v("count")]),t._v(", "),a("code",[t._v("now")]),t._v(", "),a("code",[t._v("max")]),t._v(" , "),a("code",[t._v("concat")]),t._v("같은 SQL 함수를 백엔드별로 적절한 데이터 타입을 제공합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" postgresql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("postgresql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT now() AS now_1\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" oracle\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("now"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("oracle"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT CURRENT_TIMESTAMP AS now_1 FROM DUAL\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"functions-have-return-types"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#functions-have-return-types"}},[t._v("#")]),t._v(" Functions Have Return Types")]),t._v(" "),a("blockquote",[a("p",[t._v("원문의 Functions Have Return Types 부분은 제가 이해하지 못했습니다.\n이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"built-in-functions-have-pre-configured-return-types"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#built-in-functions-have-pre-configured-return-types"}},[t._v("#")]),t._v(" Built-in Functions Have Pre-Configured Return Types")]),t._v(" "),a("blockquote",[a("p",[t._v("원문의 Built-in Functions Have Pre-Configured Return Types 부분은 제가 이해하지 못했습니다.\n이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"윈도우-함수"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#윈도우-함수"}},[t._v("#")]),t._v(" 윈도우 함수")]),t._v(" "),a("p",[t._v("윈도우 함수는 GROUP BY와 비슷한 함수이고 행간의 관계를 쉽게 정의 하기 위해 만든 함수입니다."),a("br"),t._v("\n윈도우 함수에 대해 알고 싶으신 분들은 "),a("a",{attrs:{href:"https://mizykk.tistory.com/121",target:"_blank",rel:"noopener noreferrer"}},[t._v("민지님 블로그"),a("OutboundLink")],1),t._v("에 자세한 설명이 나와있으니 한 번 읽어보시고 아래의 내용들을 이어서 읽어주세요.")]),t._v(" "),a("p",[t._v("SQLAlchemy에서는, "),a("code",[t._v("func")]),t._v(" 네임스페이스에 의해 생성된 모든 SQL 함수 중 하나로\nOVER 구문을 구현하는 "),a("code",[t._v("FunctionElement.over()")]),t._v(" 메서드가 있습니다.")]),t._v(" "),a("p",[t._v("윈도우 함수 중 하나로 행의 개수를 세는 "),a("code",[t._v("row_number()")]),t._v(" 함수가 있습니다."),a("br"),t._v("\n각 행을 사용자 이름대로 그룹을 나누고 그 안에서 이메일 주소에 번호를 매길 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# FunctionElement.over.partition_by파라미터를 사용하여 ")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# PARTITION BY 절이 OVER 절에 렌더링되도록 했습니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("row_number"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("over"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("partition_by"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("p",[a("code",[t._v("FunctionElement.over.order_by")]),t._v("를 사용하여 "),a("code",[t._v("ORDER BY")]),t._v(" 절을 사용할 수도 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("over"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("order_by"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy@squirrelpower.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob@sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"within-group-filter등-특수한-지정자"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#within-group-filter등-특수한-지정자"}},[t._v("#")]),t._v(" WITHIN GROUP, FILTER등 특수한 지정자")]),t._v(" "),a("p",[a("code",[t._v("WITHIN GORUP")]),t._v("이라는 SQL 구문은 순서 집합 또는 가상 집합 그리고 집계함수와 함께 쓰입니다.\n일반적인 순서 집합 함수는 "),a("code",[t._v("percentile_cont()")]),t._v(" 그리고 "),a("code",[t._v("rank()")]),t._v("를 포함하고 있습니다.\nSQLAlchemy에서는 "),a("code",[t._v("rank")]),t._v(", "),a("code",[t._v("dense_rank")]),t._v(", "),a("code",[t._v("percentile_count")]),t._v(", "),a("code",[t._v("percentile_disc")]),t._v("가 구현되어 있고\n각각은 "),a("code",[t._v("FunctionElement.within_group()")]),t._v("메서드를 갖고 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("unnest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("percentile_disc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.25")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.75")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("within_group"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nunnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))\n"""')]),t._v("\n")])])]),a("p",[t._v('어떤 백엔드에서는 "FILTER"를 지원하는데 이는 '),a("code",[t._v("FunctionElement.filter()")]),t._v("메서드로 사용이 가능합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("filter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("filter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" \n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,\ncount(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2\nFROM user_account JOIN address ON user_account.id = address.user_id\n"""')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"table-valued-functions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#table-valued-functions"}},[t._v("#")]),t._v(" Table-Valued Functions")]),t._v(" "),a("blockquote",[a("p",[t._v("원문의 Table-Valued Functions 부분은 제가 이해하지 못했습니다.\n이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"컬럼값-함수-또는-스칼라-컬럼-테이블값-함수"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#컬럼값-함수-또는-스칼라-컬럼-테이블값-함수"}},[t._v("#")]),t._v(" 컬럼값 함수 또는 스칼라 컬럼(테이블값 함수)")]),t._v(" "),a("p",[t._v("Oracle과 PostgresSQL에서 지원하는 특별 문법 중 하나로 FROM절에 세팅되는 함수들이 있습니다."),a("br"),t._v("\nPostgreSQL에서는 "),a("code",[t._v("json_array_elements()")]),t._v(", "),a("code",[t._v("json_object_keys()")]),t._v(", "),a("code",[t._v("json_each_text()")]),t._v(", "),a("code",[t._v("json_each()")]),t._v("등의 함수가 그 예입니다.")]),t._v(" "),a("p",[t._v("SQLAlchemy는 이러한 함수를 컬럼 값이라고 하며 "),a("code",[t._v("Function")]),t._v("객체에 지정자로 "),a("code",[t._v("FunctionElement.column_valued()")]),t._v("로 적용하여 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" func\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("json_array_elements"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('\'["one", "two"]\'')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("column_valued"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"x"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT x\nFROM json_array_elements(:json_array_elements_1) AS x\n"""')]),t._v("\n")])])]),a("p",[t._v("컬럼값 함수는 오라클에서도 아래와 같이 커스텀 SQL 함수로 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" oracle\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("func"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("scalar_strings"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("column_valued"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("oracle"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nSELECT COLUMN_VALUE s\nFROM TABLE (scalar_strings(:scalar_strings_1)) s\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/27.a111ddcb.js b/assets/js/27.a111ddcb.js new file mode 100644 index 0000000..448a157 --- /dev/null +++ b/assets/js/27.a111ddcb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{419:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"core-방식으로-행-삽입하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#core-방식으로-행-삽입하기"}},[t._v("#")]),t._v(" Core 방식으로 행 삽입하기")]),t._v(" "),a("p",[t._v("이번 챕터에서는 SQLAlchemy Core 방식으로 데이터를 INSERT 하는 방법을 배웁니다.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"insert-를-통한-sql-표현식-구성"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#insert-를-통한-sql-표현식-구성"}},[t._v("#")]),t._v(" "),a("code",[t._v("insert()")]),t._v(" 를 통한 SQL 표현식 구성")]),t._v(" "),a("p",[t._v("먼저 다음처럼 INSERT 구문을 만들 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" insert\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# stmt는 Insert 객체 인스턴스입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Spongebob Squarepants"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)'")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("여기서 "),a("code",[t._v("user_table")]),t._v("은 우리가 이전 챕터에서 만든 "),a("code",[t._v("Table")]),t._v(" 객체입니다. 우리는 아래처럼 만들었었습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" MetaData\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String\n\nmetadata "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MetaData"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nuser_table "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'user_account'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n metadata"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Integer"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" primary_key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Column"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" String"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),a("p",[a("code",[t._v("stmt")]),t._v(" 를 보면 아직 매개변수가 매핑되지는 않았습니다."),a("br"),t._v("\n이는 다음처럼 "),a("code",[t._v("complie()")]),t._v(" 한 후에 확인할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" compiled "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("compiled"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"명령문-실행"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#명령문-실행"}},[t._v("#")]),t._v(" 명령문 실행")]),t._v(" "),a("p",[t._v("이제 위에서 만든 INSERT 구문을 Core 방식으로 실행해봅시다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 위 코드는 결과적으로 아래 쿼리를 실행합니다.")]),t._v("\nBEGIN "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nINSERT INTO user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" VALUES "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Spongebob Squarepants'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nCOMMIT\n")])])]),a("p",[a("code",[t._v("conn.execute(stmt)")]),t._v(" 의 반환 값을 받은 "),a("code",[t._v("result")]),t._v(" 에는 어떤 정보가 있을까요?"),a("br"),t._v(" "),a("code",[t._v("result")]),t._v(" 는 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.CursorResult",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("CursorResult")]),a("OutboundLink")],1),t._v(" 객체입니다."),a("br"),t._v("\n여기에는 실행 결과물에 대한 여러 정보를 담고있는데, 특히 데이터 행을 담고있는 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Row",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Row")]),a("OutboundLink")],1),t._v(" 객체를 들고있습니다.")]),t._v(" "),a("p",[t._v("우리는 방금 데이터를 삽입했고, 이에 대한 결과물로 다음처럼 삽입된 데이터의 기본 키 값을 확인할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("inserted_primary_key "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 이 역시 Row 객체입니다.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 기본 키가 여러 열로 구성될 수 있으므로 튜플로 표현됩니다.")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"connection-execute-에-insert-매개변수-전달하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#connection-execute-에-insert-매개변수-전달하기"}},[t._v("#")]),t._v(" "),a("code",[t._v("Connection.execute()")]),t._v(" 에 INSERT 매개변수 전달하기")]),t._v(" "),a("p",[t._v("위에서는 다음처럼 "),a("code",[t._v("insert")]),t._v(" 에 "),a("code",[t._v("values")]),t._v(" 까지 함께 포함하여 구문울 만들었습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'spongebob'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Spongebob Squarepants"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("p",[t._v("하지만 이 방법 외에도 다음처럼 "),a("code",[t._v("Connection.execute()")]),t._v(" 메서드에 매개변수를 전달하여 INSERT 구문을 실행할 수 있습니다."),a("br"),t._v("\n공식문서에는 이게 좀 더 일반적인 방법이라고 말합니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("connect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"fullname"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Sandy Cheeks"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"patrick"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"fullname"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Patrick Star"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("공식문서에는 하위 쿼리까지 포함하여 실행시키는 법을 별도의 블락에서 설명하고 있는데, 튜토리얼 내용으로는 다소 적합하지 않다고 판단하여 이 글에는 포함하지 않았습니다.\n이 내용이 궁금하신 분들은 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/data_insert.html#insert-usually-generates-the-values-clause-automatically",target:"_blank",rel:"noopener noreferrer"}},[t._v("원문 링크"),a("OutboundLink")],1),t._v("를 참고하세요.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"insert-from-select"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#insert-from-select"}},[t._v("#")]),t._v(" "),a("code",[t._v("Insert.from_select()")])]),t._v(" "),a("p",[t._v("다음처럼 SELECT 하여 받은 행들을 INSERT 하기 위한 쿼리가 필요한 경우가 있습니다.")]),t._v(" "),a("p",[t._v("이런 사례는 예를 들면 다음 코드처럼 작성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" select_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"@aol.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" insert_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("from_select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"user_id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"email_address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" select_stmt\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("insert_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nINSERT INTO address (user_id, email_address)\nSELECT user_account.id, user_account.name || :name_1 AS anon_1\nFROM user_account\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"insert-returning"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#insert-returning"}},[t._v("#")]),t._v(" "),a("code",[t._v("Insert.returning()")])]),t._v(" "),a("p",[t._v("데이터베이스에서 쿼리 처리 후에 처리된 행의 값을 반환받아야 하는 경우가 있습니다. 이를 "),a("code",[t._v("RETURNING")]),t._v(" 문법이라 합니다."),a("br"),t._v("\n이에 대한 소개 글은 "),a("a",{attrs:{href:"https://blog.gaerae.com/2015/10/postgresql-insert-update-returning.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("이 블로그 글"),a("OutboundLink")],1),t._v("을 읽어보시면 좋을거 같습니다.")]),t._v(" "),a("p",[t._v("SQLAlchemy Core에서는 이런 "),a("code",[t._v("RETURNING")]),t._v(" 문법을 다음처럼 작성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" insert_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" insert"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("insert_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nINSERT INTO address (id, user_id, email_address)\nVALUES (:id, :user_id, :email_address)\nRETURNING address.id, address.email_address\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/28.b809fce0.js b/assets/js/28.b809fce0.js new file mode 100644 index 0000000..398fedc --- /dev/null +++ b/assets/js/28.b809fce0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{423:function(t,s,a){"use strict";a.r(s);var n=a(56),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"core-방식으로-행-수정-및-삭제하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#core-방식으로-행-수정-및-삭제하기"}},[t._v("#")]),t._v(" Core 방식으로 행 수정 및 삭제하기")]),t._v(" "),a("p",[t._v("이번 챕터에서는 Core 방식으로 기존 행을 수정하고 삭제하는 데 사용되는 Update 및 Delete 구문에 대해 설명합니다.")]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"update-를-통한-sql-표현식-구성"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#update-를-통한-sql-표현식-구성"}},[t._v("#")]),t._v(" "),a("code",[t._v("update()")]),t._v(" 를 통한 SQL 표현식 구성")]),t._v(" "),a("p",[t._v("다음처럼 UPDATE 구문을 작성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" update\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Patrick the Star'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1'")]),t._v("\n")])])]),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Username: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'UPDATE user_account SET fullname=(:name_1 || user_account.name)'")]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("원문에는 "),a("code",[t._v("bindparam()")]),t._v(" 에 대한 내용이 나오는데, 사용 사례를 잘 본 적이 없어서 이 글에서는 생략합니다. 궁금하신 분은 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/data_update.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("원문 내용"),a("OutboundLink")],1),t._v("을 참고하세요.")])]),t._v(" "),a("br"),t._v(" "),a("h3",{attrs:{id:"correlated-업데이트"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#correlated-업데이트"}},[t._v("#")]),t._v(" Correlated 업데이트")]),t._v(" "),a("p",[t._v("다음처럼 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/data_select.html#tutorial-scalar-subquery",target:"_blank",rel:"noopener noreferrer"}},[t._v("Correlated Subquery"),a("OutboundLink")],1),t._v("를 사용하여 다른 테이블의 행을 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" scalar_subq "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" limit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" scalar_subquery"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("scalar_subq"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=(SELECT address.email_address\nFROM address\nWHERE address.user_id = user_account.id ORDER BY address.id\nLIMIT :param_1)\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"다른-테이블과-연관된-조건으로-업데이트"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#다른-테이블과-연관된-조건으로-업데이트"}},[t._v("#")]),t._v(" 다른 테이블과 연관된 조건으로 업데이트")]),t._v(" "),a("p",[t._v("테이블을 업데이트할 때, 다른 테이블의 정보와 연관하여 조건을 설정해야할 때가 있습니다."),a("br"),t._v("\n이 경우, 예를들면 다음처럼 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Pat'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=:fullname FROM address\nWHERE user_account.id = address.user_id AND address.email_address = :email_address_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"여러-테이블-동시에-업데이트"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#여러-테이블-동시에-업데이트"}},[t._v("#")]),t._v(" 여러 테이블 동시에 업데이트")]),t._v(" "),a("p",[t._v("다음처럼 여러 테이블에서 조건에 해당하는 특정 값들을 동시에 업데이트할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Pat"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pat@aol.com"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mysql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("mysql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account, address\nSET address.email_address=%s, user_account.fullname=%s\nWHERE user_account.id = address.user_id AND address.email_address = %s\n"""')]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("원문의 Parameter Ordered Updates 부분은 제가 이해하지 못하여 정리하지 않았습니다."),a("br"),t._v("\n잘 아시는 분이 있으면 이 문서에 기여해주시면 감사하겠습니다.")])]),t._v(" "),a("br"),t._v(" "),a("h2",{attrs:{id:"delete-를-통한-sql-표현식-구성"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#delete-를-통한-sql-표현식-구성"}},[t._v("#")]),t._v(" "),a("code",[t._v("delete()")]),t._v(" 를 통한 SQL 표현식 구성")]),t._v(" "),a("p",[t._v("다음처럼 DELETE 구문을 작성할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" delete\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account WHERE user_account.name = :name_1\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h3",{attrs:{id:"다른-테이블과-조인하여-삭제"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#다른-테이블과-조인하여-삭제"}},[t._v("#")]),t._v(" 다른 테이블과 조인하여 삭제")]),t._v(" "),a("p",[t._v("다른 테이블과 조인한 뒤, 특정 조건에 맞는 데이터만 삭제해야 하는 경우가 있습니다. (이해가 안간다면 "),a("a",{attrs:{href:"https://servedev.tistory.com/61",target:"_blank",rel:"noopener noreferrer"}},[t._v("이 글"),a("OutboundLink")],1),t._v("을 참고해보세요.)\n이 경우, 예를들면 다음처럼 사용할 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" delete_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("address_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialects "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mysql\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("delete_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("compile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("mysql"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("dialect"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account USING user_account, address\nWHERE user_account.id = address.user_id AND address.email_address = %s\n"""')]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"update-delete에서-영향을-받는-행-수-얻기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#update-delete에서-영향을-받는-행-수-얻기"}},[t._v("#")]),t._v(" UPDATE, DELETE에서 영향을 받는 행 수 얻기")]),t._v(" "),a("p",[t._v("다음처럼 "),a("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.CursorResult.rowcount",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Result.rowcount")]),t._v(" 속성"),a("OutboundLink")],1),t._v("을 통해 쿼리가 처리한 행 수를 가져올 수 있습니다.")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("begin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" conn"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Patrick McStar"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rowcount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Result 객체의 rowcount 속성을 사용합니다.")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 쿼리가 처리한 행 수 (조건절에 걸리는 행 수와 같습니다.)")]),t._v("\n")])])]),a("br"),t._v(" "),a("h2",{attrs:{id:"update-delete와-함께-returning-사용하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#update-delete와-함께-returning-사용하기"}},[t._v("#")]),t._v(" UPDATE, DELETE와 함께 RETURNING 사용하기")]),t._v(" "),a("p",[t._v("다음처럼 RETURNING 문법을 사용할 수 있습니다. (RETURNING 문법에 대해서는 "),a("a",{attrs:{href:"https://blog.gaerae.com/2015/10/postgresql-insert-update-returning.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("이 글"),a("OutboundLink")],1),t._v("을 참고해보세요.)")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" update_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Patrick the Star'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("update_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nUPDATE user_account SET fullname=:fullname\nWHERE user_account.name = :name_1\nRETURNING user_account.id, user_account.name\n"""')]),t._v("\n")])])]),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" delete_stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" returning"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" user_table"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("delete_stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\nDELETE FROM user_account\nWHERE user_account.name = :name_1\nRETURNING user_account.id, user_account.name\n"""')]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/29.7029d8fa.js b/assets/js/29.7029d8fa.js new file mode 100644 index 0000000..7a8038b --- /dev/null +++ b/assets/js/29.7029d8fa.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{424:function(s,t,a){"use strict";a.r(t);var n=a(56),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"orm-방식으로-데이터-조작하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-방식으로-데이터-조작하기"}},[s._v("#")]),s._v(" ORM 방식으로 데이터 조작하기")]),s._v(" "),a("p",[s._v("이전 챕터까지 CORE 관점에서 쿼리를 활용하는 방식에 초점을 맞췄습니다. 이번 챕터에서는 ORM 방식에서 쓰이는 "),a("code",[s._v("Session")]),s._v("의 구성 요소와 수명 주기, 상호 작용하는 방법을 설명합니다.")]),s._v(" "),a("br"),s._v(" "),a("h2",{attrs:{id:"orm으로-행-삽입하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm으로-행-삽입하기"}},[s._v("#")]),s._v(" ORM으로 행 삽입하기")]),s._v(" "),a("p",[a("code",[s._v("Session")]),s._v(" 객체는 ORM을 사용할 때 "),a("code",[s._v("Insert")]),s._v(" 객체들을 만들고 트랜잭션에서 이 객체들을 내보내는 역할을 합니다.\n"),a("code",[s._v("Session")]),s._v("은 이러한 과정들을 수행하기 위해 객체 항목을 추가합니다.\n그 후 flush라는 프로세스를 통해 새로운 항목들을 데이터베이스에 기록합니다.")]),s._v(" "),a("h3",{attrs:{id:"행을-나타내는-객체의-인스턴스"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#행을-나타내는-객체의-인스턴스"}},[s._v("#")]),s._v(" 행을 나타내는 객체의 인스턴스")]),s._v(" "),a("p",[s._v("이전 과정에서 우리는 "),a("code",[s._v("Python Dict")]),s._v("를 사용하여 "),a("code",[s._v("INSERT")]),s._v("를 실행하였습니다.")]),s._v(" "),a("p",[s._v("ORM에서는 테이블 메타데이터 정의에서 정의한 사용자 정의 Python 객체를 직접 사용합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"squidward"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Squidward Tentacles"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" krabs "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"ehkrabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Eugene H. Krabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[a("code",[s._v("INSERT")]),s._v(" 될 잠재적인 데이터베이스 행을 나타내는 두 개의 "),a("code",[s._v("User")]),s._v(" 객체를 만듭니다.\nORM 매핑에 의해 자동으로 생성된 "),a("code",[s._v("__init__()")]),s._v(" 생성자 덕에 생성자의 열 이름을 키로 사용하여 각 객체를 생성할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("Core의 "),a("code",[s._v("Insert")]),s._v("와 유사하게, 기본 키를 포함하지 않아도 ORM이 이를 통합시켜 줍니다.\n"),a("code",[s._v("id")]),s._v("의 "),a("code",[s._v("None")]),s._v(" 값은 속성에 아직 값이 없음을 나타내기 위해 SQLAlchemy에서 제공합니다.")]),s._v(" "),a("p",[s._v("현재 위의 두 객체("),a("code",[s._v("squiward")]),s._v("와 "),a("code",[s._v("krabs")]),s._v(")는 "),a("code",[s._v("transient")]),s._v(" 상태라고 불리게 됩니다.\n"),a("code",[s._v("transient")]),s._v(" 상태란, 어떤 데이터베이스와 연결되지 않고, "),a("code",[s._v("INSERT")]),s._v("문을 생성할 수 있는 "),a("code",[s._v("Session")]),s._v("객체와도 아직 연결되지 않은 상태를 의미합니다.")]),s._v(" "),a("h3",{attrs:{id:"session에-객체-추가하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#session에-객체-추가하기"}},[s._v("#")]),s._v(" "),a("code",[s._v("Session")]),s._v("에 객체 추가하기")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 반드시 사용 후 close 해야 합니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Session.add() 매소드를 통해서 객체를 Session에 추가해줍니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("krabs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("객체가 "),a("code",[s._v("Session.add()")]),s._v("를 통해서 "),a("code",[s._v("Session")]),s._v("에 추가하게 되면, "),a("code",[s._v("pending")]),s._v(" 상태가 되었다고 부릅니다.\n"),a("code",[s._v("pending")]),s._v(" 상태는 아직 데이터베이스에 추가되지 않은 상태입니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("new "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# session.new를 통해서 pending 상태에 있는 객체들을 확인할 수 있습니다.")]),s._v("\nIdentitySet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'ehkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Eugene H. Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("ul",[a("li",[a("code",[s._v("IdentitySet")]),s._v("은 모든 경우에 객체 ID를 hash하는 Python "),a("code",[s._v("set")]),s._v("입니다.")]),s._v(" "),a("li",[s._v("즉, Python 내장 함수 중 "),a("code",[s._v("hash()")]),s._v("가 아닌, "),a("code",[s._v("id()")]),s._v(" 메소드를 사용하고 있습니다.")])]),s._v(" "),a("h3",{attrs:{id:"flushing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#flushing"}},[s._v("#")]),s._v(" Flushing")]),s._v(" "),a("p",[a("code",[s._v("Session")]),s._v(" 객체는 "),a("a",{attrs:{href:"https://zetlos.tistory.com/1179902868",target:"_blank",rel:"noopener noreferrer"}},[a("code",[s._v("unit of work")]),s._v(" 패턴"),a("OutboundLink")],1),s._v("을 사용합니다. 이는 변경 사항을 누적하지만, 필요할 때까지는 실제로 데이터베이스와 통신을 하지 않음을 의미합니다.\n이런 동작 방식을 통해서 위에서 언급한 "),a("code",[s._v("pending")]),s._v(" 상태의 객체들이 더 효율적인 SQL DML로 사용됩니다.\n현재의 변경된 사항들을 실제로 Database에 SQL을 통해 내보내는 작업을 flush 이라고 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("flush"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v("\"\"\"\nINSERT INTO user_account (name, fullname) VALUES (?, ?)\n[...] ('squidward', 'Squidward Tentacles')\nINSERT INTO user_account (name, fullname) VALUES (?, ?)\n[...] ('ehkrabs', 'Eugene H. Krabs')\n\"\"\"")]),s._v("\n")])])]),a("p",[s._v("이제 트랜잭션은 "),a("code",[s._v("Session.commit()")]),s._v(", "),a("code",[s._v("Session.rollback()")]),s._v(", "),a("code",[s._v("Session.close()")]),s._v(" 중 하나가 호출될 때 까지 열린 상태로 유지됩니다.")]),s._v(" "),a("p",[a("code",[s._v("Session.flush()")]),s._v("를 직접 사용하여, 현재 "),a("code",[s._v("pending")]),s._v(" 상태에 있는 내용을 직접 밀어넣을 수 있지만, Session은 autoflush라는 동작을 특징으로 하므로 일반적으로는 필요하지 않습니다. "),a("code",[s._v("Session.commit()")]),s._v("이 호출 될 때 마다 변경 사항을 flush 합니다.")]),s._v(" "),a("h3",{attrs:{id:"자동-생성된-기본-키-속성"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#자동-생성된-기본-키-속성"}},[s._v("#")]),s._v(" 자동 생성된 기본 키 속성")]),s._v(" "),a("p",[s._v("행이 삽입되게 되면, 우리가 생성한 Python 객체는 "),a("code",[s._v("persistent")]),s._v(" 라는 상태가 됩니다.\n"),a("code",[s._v("persistent")]),s._v(" 상태는 로드된 "),a("code",[s._v("Session")]),s._v(" 객체와 연결됩니다.")]),s._v(" "),a("p",[a("code",[s._v("INSERT")]),s._v(" 실행 시, ORM이 각각의 새 객체에 대한 기본 키 식별자를 검색하는 효과를 가져옵니다.\n이전에 소개한것과 동일한 "),a("code",[s._v("CursorResult.inserted_primary_key")]),s._v(" 접근자를 사용합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" krabs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("ORM이 flush 될 때, "),a("code",[s._v("executemany")]),s._v(" 대신, 두 개의 다른 INSERT 문을 사용하는 이유가 바로 이 "),a("code",[s._v("CursorResult.inserted_primary_key")]),s._v(" 때문입니다.")]),s._v(" "),a("ul",[a("li",[s._v("SQLite의 경우 한 번에 한 열을 "),a("code",[s._v("INSERT")]),s._v(" 해야 자동 증가 기능을 사용할 수 있습니다.(PostgreSQL의 IDENTITY나 SERIAL 기능등 다른 다양한 데이터베이스들의 경우들도 이처럼 동작합니다.)")]),s._v(" "),a("li",[a("code",[s._v("psycopg2")]),s._v("와 같이 한번에 많은 데이터에 대한 기본 키 정보를 제공 받을 수 있는 데이터베이스가 연결되어 있다면, ORM은 이를 최적화하여 많은 열을 한번에 "),a("code",[s._v("INSERT")]),s._v(" 하도록 합니다.")])])]),s._v(" "),a("h3",{attrs:{id:"identity-map"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#identity-map"}},[s._v("#")]),s._v(" Identity Map")]),s._v(" "),a("p",[a("code",[s._v("Identity Map")]),s._v("("),a("code",[s._v("ID Map")]),s._v(")은 현재 메모리에 로드된 모든 객체를 기본 키 ID에 연결하는 메모리 내 저장소입니다.\n"),a("code",[s._v("Session.get()")]),s._v("을 통해서 객체 중 하나를 검색할 수 있습니다.\n이 메소드는 객체가 메모리에 있으면, "),a("code",[s._v("ID Map")]),s._v("에서, 그렇지 않으면 "),a("code",[s._v("SELECT")]),s._v("문을 통해서 객체를 검색합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" some_squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" some_squidward\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'squidward'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("중요한 점은, "),a("code",[s._v("ID Map")]),s._v("은 Python 객체 중에서도 고유한 객체를 유지하고 있다는 점입니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" some_squidward "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("is")]),s._v(" squidward \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n")])])]),a("p",[a("code",[s._v("ID map")]),s._v("은 동기화되지 않은 상태에서, 트랜잭션 내에서 복잡한 개체 집합을 조작할 수 있도록 하는 중요한 기능입니다.")]),s._v(" "),a("h3",{attrs:{id:"committing"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#committing"}},[s._v("#")]),s._v(" Committing")]),s._v(" "),a("p",[s._v("현재까지의 변경사항을 트랜잭션에 "),a("code",[s._v("commit")]),s._v(" 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nCOMMIT\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"orm-객체-update하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-객체-update하기"}},[s._v("#")]),s._v(" ORM 객체 "),a("code",[s._v("UPDATE")]),s._v("하기")]),s._v(" "),a("p",[s._v("ORM을 통해 "),a("code",[s._v("UPDATE")]),s._v(" 하는 방법에는 2가지 방법이 있습니다.")]),s._v(" "),a("ol",[a("li",[a("code",[s._v("Session")]),s._v("에서 사용하는 "),a("code",[s._v("unit of work")]),s._v(" 패턴 방식이 있습니다. 변경사항이 있는 기본 키 별로 "),a("code",[s._v("UPDATE")]),s._v(" 작업이 순서대로 내보내지게 됩니다.")]),s._v(" "),a("li",[s._v('"ORM 사용 업데이트"라고 하며 명시적으로 Session과 함께 '),a("code",[s._v("Update")]),s._v(" 구성을 사용할 수도 있습니다.")])]),s._v(" "),a("h3",{attrs:{id:"변경사항을-자동으로-업데이트하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#변경사항을-자동으로-업데이트하기"}},[s._v("#")]),s._v(" 변경사항을 자동으로 업데이트하기")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("filter_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'sandy\',)\n"""')]),s._v("\n")])])]),a("p",[s._v("이 'Sandy' 유저 객체는 데이터베이스에서 행, 더 구체적으로는 트랙잭션 측면에서 기본 키가 2인 행에 대한 "),a("code",[s._v("proxy")]),s._v(" 역할을 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Sandy Squirrel"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 객체의 속성을 변화시키면, Session은 이 변화를 기록합니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("dirty "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 이렇게 변한 객체는 dirty 라고 불리우며 session.dirty에서 확인 할 수 있습니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n")])])]),a("p",[s._v("Session이 "),a("code",[s._v("flush")]),s._v("를 실행하게 되면, 데이터베이스에서 "),a("code",[s._v("UPDATE")]),s._v("가 실행되어 데이터베이스에 실제로 값을 갱신합니다. "),a("code",[s._v("SELECT")]),s._v(" 문을 추가로 실행하게 되면, 자동으로 "),a("code",[s._v("flush")]),s._v("가 실행되어 sandy의 바뀐 이름 값을 "),a("code",[s._v("SELECT")]),s._v("를 통해서 바로 얻을 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy_fullname "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nUPDATE user_account SET fullname=? WHERE user_account.id = ?\n[...] (\'Sandy Squirrel\', 2)\nSELECT user_account.fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (2,)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("sandy_fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nSandy Squirrel\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# flush를 통해 sandy의 변화가 실제로 데이터베이스에 반영되어, dirty 속성을 잃게 됩니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("dirty \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("False")]),s._v("\n")])])]),a("h3",{attrs:{id:"orm-사용-업데이트"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-사용-업데이트"}},[s._v("#")]),s._v(" ORM 사용 업데이트")]),s._v(" "),a("p",[s._v("ORM을 통해 "),a("code",[s._v("UPDATE")]),s._v(" 하는 마지막 방법으로 "),a("code",[s._v("ORM 사용 업데이트")]),s._v("를 명시적으로 사용하는 방법이 있습니다. 이를 사용하면 한 번에 많은 행에 영향을 줄 수 있는 일반 SQL "),a("code",[s._v("UPDATE")]),s._v(" 문을 사용할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" update"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"sandy"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" values"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Sandy Squirrel Extraordinaire"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nUPDATE user_account SET fullname=? WHERE user_account.name = ?\n[...] (\'Sandy Squirrel Extraordinaire\', \'sandy\')\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("engine"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("cursor"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("CursorResult "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("object")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n")])])]),a("p",[s._v("현재 "),a("code",[s._v("Session")]),s._v("에서 주어진 조건과 일치하는 객체가 있다면, 이 객체에도 해당하는 "),a("code",[s._v("update")]),s._v("가 반영되게 됩니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Sandy Squirrel Extraordinaire'")]),s._v("\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"orm-객체를-삭제하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-객체를-삭제하기"}},[s._v("#")]),s._v(" ORM 객체를 삭제하기")]),s._v(" "),a("p",[a("code",[s._v("Session.delete()")]),s._v(" 메서드를 사용하여 개별 ORM 객체를 삭제 대상으로 표시할 수 있습니다. "),a("code",[s._v("delete")]),s._v("가 수행되면, 해당 "),a("code",[s._v("Session")]),s._v("에 존재하는 객체들은 "),a("code",[s._v("expired")]),s._v(" 상태가 되게 됩니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" patrick "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (3,)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("patrick"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# patrik을 삭제 할 것이라고 명시")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"patrick"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 이 시점에서 flush 실행")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT address.id AS address_id, address.email_address AS address_email_address,\naddress.user_id AS address_user_id\nFROM address\nWHERE ? = address.user_id\n[...] (3,)\nDELETE FROM user_account WHERE user_account.id = ?\n[...] (3,)\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'patrick\',)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Session에서 만료되면, 해당 객체는 session에서 삭제됩니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("False")]),s._v("\n")])])]),a("p",[s._v("위의 "),a("code",[s._v("UPDATE")]),s._v("에서 사용된 'Sandy'와 마찬가지로, 해당 작업들은 진행중인 트랜잭션에서만 이루어진 일이며 "),a("code",[s._v("commit")]),s._v(" 하지 않는 이상, 언제든 취소할 수 있습니다.")]),s._v(" "),a("h3",{attrs:{id:"orm-사용-삭제하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm-사용-삭제하기"}},[s._v("#")]),s._v(" ORM 사용 삭제하기")]),s._v(" "),a("p",[a("code",[s._v("UPDATE")]),s._v("와 마찬가지로 "),a("code",[s._v("ORM 사용 삭제하기")]),s._v("도 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 예시를 위한 작업일 뿐, 실제로 delete에서 필요한 작업은 아닙니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("get"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (4,)\n"""')]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("delete"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"squidward"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nDELETE FROM user_account WHERE user_account.name = ?\n[...] (\'squidward\',)\n\n"""')]),s._v("\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"rolling-back"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rolling-back"}},[s._v("#")]),s._v(" Rolling Back")]),s._v(" "),a("p",[a("code",[s._v("Session")]),s._v("에는 현재의 작업들을 롤백하는 "),a("code",[s._v("Session.rollback()")]),s._v(" 메소드가 존재합니다. 이 메소드는 위에서 사용된 "),a("code",[s._v("sandy")]),s._v("와 같은 Python 객체에도 영향을 미칩니다.\n"),a("code",[s._v("Session.rollback()")]),s._v("을 호출하면 트랜잭션을 롤백할 뿐만 아니라 현재 이 "),a("code",[s._v("Session")]),s._v("과 연결된 모든 객체를 "),a("code",[s._v("expired")]),s._v(" 상태로 바꿉니다. 이러한 상태 변경은 다음에 객체에 접근 할 때 스스로 새로 고침을 하는 효과가 있고 이러한 프로세스를 "),a("code",[s._v("지연 로딩")]),s._v(" 이라고 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("rollback"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nROLLBACK\n")])])]),a("p",[a("code",[s._v("expired")]),s._v(" 상태의 객체인 "),a("code",[s._v("sandy")]),s._v(" 를 자세히 보면, 특별한 SQLAlchemy 관련 상태 객체를 제외하고 다른 정보가 남아 있지 않음을 볼 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("__dict__\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'_sa_instance_state'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("state"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("InstanceState "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("object")]),s._v(" at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# session이 만료되었으므로, 해당 객체 속성에 접근 시, 트랜잭션이 새로 일어납니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name,\nuser_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (2,)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Sandy Cheeks'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("__dict__ "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#이제 데이터베이스 행이 sandy 객체에도 채워진 것을 볼 수 있습니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'_sa_instance_state'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("state"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("InstanceState "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("object")]),s._v(" at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'id'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'name'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'sandy'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'fullname'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Sandy Cheeks'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])])]),a("p",[s._v("삭제된 객체에 대해서도, "),a("code",[s._v("Session")]),s._v("에 다시 복원되었으며 데이터베이스에도 다시 나타나는 걸 볼 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" patrick "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'patrick'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalar_one"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("is")]),s._v(" patrick\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id, user_account.name, user_account.fullname\nFROM user_account\nWHERE user_account.name = ?\n[...] (\'patrick\',)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"session-종료하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#session-종료하기"}},[s._v("#")]),s._v(" "),a("code",[s._v("Session")]),s._v(" 종료하기")]),s._v(" "),a("p",[s._v("우리는 컨텍스트 구문 외부에서 "),a("code",[s._v("Session")]),s._v("을 다뤘는데, 이런 경우 다음처럼 명시적으로 "),a("code",[s._v("Session")]),s._v("을 닫아주는 것이 좋습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("close"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nROLLBACK\n")])])]),a("p",[s._v("마찬가지로 컨텍스트 구문을 통해 생성한 "),a("code",[s._v("Session")]),s._v("을 컨텍스트 구문 내에서 닫으면 다음 작업들이 수행됩니다.")]),s._v(" "),a("ul",[a("li",[s._v("진행 중인 모든 트랜잭션을 취소(예: 롤백)하여 연결 풀에 대한 모든 연결 리소스를 해제합니다.\n"),a("ul",[a("li",[s._v("즉, "),a("code",[s._v("Session")]),s._v("을 사용하여 일부 읽기 전용 작업을 수행한 다음, 닫을 때 트랜잭션이 롤백되었는지 확인하기 위해 "),a("code",[s._v("Session.rollback()")]),s._v("을 명시적으로 호출할 필요가 없습니다. 연결 풀이 이를 처리합니다.")])])]),s._v(" "),a("li",[a("code",[s._v("Session")]),s._v("에서 모든 개체를 삭제합니다.\n"),a("ul",[a("li",[s._v("이것은 sandy, patrick 및 squidward와 같이 이 "),a("code",[s._v("Session")]),s._v("에 대해 로드한 모든 Python 개체가 이제 "),a("code",[s._v("detached")]),s._v(" 상태에 있음을 의미합니다. 예를 들어 "),a("code",[s._v("expired")]),s._v(" 상태에 있던 객체는 "),a("code",[s._v("Session.commit()")]),s._v(" 호출로 인해 현재 행의 상태를 포함하지 않고 새로 고칠 데이터베이스 트랜잭션과 더 이상 연관되지 않습니다.")]),s._v(" "),a("li",[a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name\nTraceback "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("most recent call last"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\nsqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("exc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("DetachedInstanceError"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Instance "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("User at 0x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("is")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("not")]),s._v(" bound to a Session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" attribute refresh operation cannot proceed\n")])])])]),s._v(" "),a("li",[a("code",[s._v("detached")]),s._v("된 객체는 "),a("code",[s._v("Session.add()")]),s._v(" 메서드를 사용하여 동일한 객체 또는 새 "),a("code",[s._v("Session")]),s._v("과 다시 연결될 수 있습니다. 그러면 특정 데이터베이스 행과의 관계가 다시 설정됩니다.")]),s._v(" "),a("li",[a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# session에 다시 연결")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" squidward"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 트랜잭션을 통해 정보를 다시 불러옵니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[s._v('"""\nSELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname\nFROM user_account\nWHERE user_account.id = ?\n[...] (4,)\n"""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'squidward'")]),s._v("\n")])])])])])])]),s._v(" "),a("blockquote",[a("p",[a("code",[s._v("detached")]),s._v(" 상태의 개체는 되도록이면 사용을 지양해야 합니다. "),a("code",[s._v("Session")]),s._v("이 닫히면 이전에 연결된 모든 개체에 대한 참조도 정리합니다. 일반적으로 "),a("code",[s._v("detached")]),s._v("된 객체가 필요한 경우는 웹 어플리케이션에서 방금 커밋된 개체를 뷰에서 렌더링되기 전에 "),a("code",[s._v("Session")]),s._v("이 닫힌 경우가 있습니다. 이 경우 "),a("code",[s._v("Session.expire_on_commit")]),s._v(" 플래그를 False로 설정합니다.")])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/3.2e213720.js b/assets/js/3.2e213720.js new file mode 100644 index 0000000..0a04ef2 --- /dev/null +++ b/assets/js/3.2e213720.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{370:function(t,e,n){},397:function(t,e,n){"use strict";n(370)},429:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(397),n(56)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/30.b93101cb.js b/assets/js/30.b93101cb.js new file mode 100644 index 0000000..114cce4 --- /dev/null +++ b/assets/js/30.b93101cb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{426:function(s,t,a){"use strict";a.r(t);var n=a(56),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"orm으로-관련-개체-작업하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#orm으로-관련-개체-작업하기"}},[s._v("#")]),s._v(" ORM으로 관련 개체 작업하기")]),s._v(" "),a("br"),s._v(" "),a("p",[s._v("이번 챕터에서는 다른 객체를 참조하는 매핑된 객체와 상호작용하는 방식인 또 하나의 필수적인 ORM 개념을 다룰 것입니다."),a("br"),s._v(" "),a("code",[s._v("relationship()")]),s._v("은 매핑된 두 객체 간의 관계를 정의하며, "),a("strong",[s._v("자기 참조")]),s._v("관계라고도 합니다."),a("br"),s._v("\n기본적인 구조를 위해 "),a("code",[s._v("Column")]),s._v(" 매핑 및 기타 지시문을 생략하고 짧은 형식으로 "),a("code",[s._v("relationship()")]),s._v("을 설명드리겠습니다.")]),s._v(" "),a("br"),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" relationship\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'user_account'")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ... Column mappings")]),s._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Address")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'address'")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ... Column mappings")]),s._v("\n\n user "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"User"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("br"),s._v(" "),a("p",[s._v("위 구조를 보면 "),a("code",[s._v("User")]),s._v(" 객체에는 "),a("code",[s._v("addresses")]),s._v(" 변수, "),a("code",[s._v("Address")]),s._v(" 객체에는 "),a("code",[s._v("user")]),s._v(" 라는 변수가 있습니다."),a("br"),s._v("\n공통적으로 "),a("code",[s._v("relationship")]),s._v(" 객체로 생성되어져 있는 것을 볼 수 있습니다.\n이는 실제 "),a("strong",[s._v("데이터베이스에 컬럼")]),s._v("으로 존재하는 변수는 아니지만 코드 상에서 쉽게 접근할 수 있도록 하기 위해 설정 되었습니다."),a("br"),s._v("\n즉, "),a("code",[s._v("User")]),s._v(" 객체에서 "),a("code",[s._v("Address")]),s._v(" 객체로 쉽게 찾아갈 수 있게 해줍니다.")]),s._v(" "),a("p",[s._v("또한 "),a("code",[s._v("relationship")]),s._v(" 선언시 파라미터로 "),a("code",[s._v("back_populates")]),s._v(" 항목은 반대의 상황 즉,\n"),a("code",[s._v("Address")]),s._v(" 객체에서 "),a("code",[s._v("User")]),s._v(" 객체를 찾아 갈 수 있게 해줍니다.")]),s._v(" "),a("blockquote",[a("p",[s._v("관계형으로 보았을 경우 1 : N 관계를 자연스럽게 N : 1 관계로 해주는 설정입니다.")])]),s._v(" "),a("p",[s._v("다음 섹션에서 "),a("code",[s._v("relationship()")]),s._v(" 객체의 인스턴스가 어떤 역할을 하는지, 동작하는지 보겠습니다.")]),s._v(" "),a("br"),s._v(" "),a("h2",{attrs:{id:"관계된-객체-사용하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#관계된-객체-사용하기"}},[s._v("#")]),s._v(" 관계된 객체 사용하기")]),s._v(" "),a("br"),s._v(" "),a("p",[s._v("새로운 "),a("code",[s._v("User")]),s._v(" 객체를 만들면 "),a("code",[s._v(".addresses")]),s._v(" 컬렉션이 나타나는데 "),a("code",[s._v("List")]),s._v(" 객체임을 알 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" \n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("p",[a("code",[s._v("list.append()")]),s._v("를 사용하여 "),a("code",[s._v("Address")]),s._v(" 객체를 추가할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"pear1.krabs@gmail.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("append"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# u1.addresses 컬렉션에 새로운 Address 객체가 포함되었습니다.")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("p",[a("code",[s._v("Address")]),s._v(" 객체를 인스턴스 "),a("code",[s._v("User.addresses")]),s._v(" 컬렉션과 연관시켰다면 변수 "),a("code",[s._v("u1")]),s._v(" 에는 또 다른 동작이 발생하는데,"),a("br"),s._v(" "),a("code",[s._v("User.addresses")]),s._v(" 와 "),a("code",[s._v("Address.user")]),s._v(" 관계가 동기화 되어")]),s._v(" "),a("ul",[a("li",[a("code",[s._v("User")]),s._v(" 객체에서 "),a("code",[s._v("Address")]),s._v(" 이동할 수 있을 뿐만 아니라")]),s._v(" "),a("li",[a("code",[s._v("Address")]),s._v(" 객체에서 다시 "),a("code",[s._v("User")]),s._v(" 객체로 이동할 수도 있습니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user\nUser"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("두개의 "),a("code",[s._v("relationshiop()")]),s._v(" 객체 간의 "),a("code",[s._v("relationship.back_populates")]),s._v(" 을 사용한 동기화 결과입니다.")]),s._v(" "),a("p",[s._v("매개변수 "),a("code",[s._v("relationshiop()")]),s._v(" 는 보완적으로 할당/목록 변형이 발생할때 다른 변수로 지정할 수 있습니다.\n다른 "),a("code",[s._v("Address")]),s._v(" 객체를 생성하고 해당 "),a("code",[s._v("Address.user")]),s._v(" 속성에 할당하면 해당 객체 "),a("code",[s._v("Address")]),s._v("에 대한 "),a("code",[s._v("User.addresses")]),s._v(" 컬렉션의 일부가 되는것도 확인 할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"pearl@aol.com"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("br"),s._v(" "),a("p",[s._v("우리는 실제로 객체("),a("code",[s._v("Address")]),s._v(")에 선언된 속성처럼 "),a("code",[s._v("user")]),s._v("의 키워드 인수로 "),a("code",[s._v("u1")]),s._v(" 변수를 사용했습니다."),a("br"),s._v("\n다음 사실 이후에 속성을 할당하는 것과 같습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# equivalent effect as a2 = Address(user=u1)")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" u1\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"session에-객체-캐스케이딩"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#session에-객체-캐스케이딩"}},[s._v("#")]),s._v(" "),a("code",[s._v("Session")]),s._v("에 객체 캐스케이딩")]),s._v(" "),a("br"),s._v(" "),a("p",[s._v("이제 메모리의 양방향 구조와 연결된 두 개의 "),a("code",[s._v("User")]),s._v(", "),a("code",[s._v("Address")]),s._v(" 객체가 있지만 이전에 "),a("RouterLink",{attrs:{to:"/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/6. ORM으로 데이터 조작하기.html#orm으로-행-삽입하기)"}},[s._v("ORM으로 행 삽입하기")]),s._v(" 에서 언급했듯이 이러한 객체는 객체와 연결될 때까지 "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/glossary.html#term-transient)"}},[s._v("일시적인")]),s._v(" "),a("code",[s._v("Session")]),s._v(" 상태에 있습니다.")],1),s._v(" "),a("p",[s._v("우리는 "),a("code",[s._v("Session.add()")]),s._v(" 를 사용하고, "),a("code",[s._v("User")]),s._v(" 객체에 메서드를 적용할 때 관련 "),a("code",[s._v("Address")]),s._v(" 객체도 추가된다는 점을 확인해 볼 필요가 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("add"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a2 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session \n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),s._v("\n")])])]),a("p",[s._v("세 개의 객체는 이제 "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/glossary.html#term-pending)"}},[s._v("보류")]),s._v(" 상태에 있으며, 이는 INSERT 작업이 진행되지 않았음을 의미합니다."),a("br"),s._v("\n세 객체는 모두 기본 키가 할당되지 않았으며, 또한 a1 및 a2 객체에는 열("),a("code",[s._v("user_id")]),s._v(")을 참조 속성이 있습니다."),a("br"),s._v("\n이는 객체가 아직 실제 데이터베이스 연결되지 않았기 때문입니다.")],1),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("None")]),s._v("\n")])])]),a("p",[s._v("데이터베이스에 저장해봅시다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("commit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("구현한 코드를 SQL 쿼리로 동작을 해본다면 이와 같습니다.")]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INSERT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INTO")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("VALUES")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INSERT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INTO")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("VALUES")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INSERT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("INTO")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("VALUES")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("COMMIT")]),s._v("\n")])])]),a("p",[a("code",[s._v("session")]),s._v("을 사용하여 SQL의 INSERT, UPDATE, DELETE 문을 자동화할 수 있습니다.\n마지막으로 "),a("code",[s._v("Session.commit()")]),s._v("을 실행하여 모든 단계를 올바른 순서로 호출되며 "),a("code",[s._v("user_account")]),s._v("에 "),a("code",[s._v("address.user_id")]),s._v(" 기본키가 적용됩니다.")]),s._v(" "),a("br"),s._v(" "),a("h2",{attrs:{id:"관계-로드"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#관계-로드"}},[s._v("#")]),s._v(" 관계 로드")]),s._v(" "),a("br"),s._v(" "),a("p",[a("code",[s._v("Session.commit()")]),s._v(" 을 호출한 이후에는 "),a("code",[s._v("u1")]),s._v(" 객체에 생성된 기본 키를 볼 수 있게됩니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BEGIN")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("implicit"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\nuser_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" ?\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("다음처럼 "),a("code",[s._v("u1.addresses")]),s._v(" 에 연결된 객체들에도 "),a("code",[s._v("id")]),s._v("가 들어와있는 것을 볼 수 있습니다.\n해당 객체를 검색하기 위해 우리는 "),a("strong",[s._v("lazy load")]),s._v(" 방식으로 볼 수 있습니다.")]),s._v(" "),a("blockquote",[a("p",[s._v("lazy loading : 누군가 해당 정보에 접근하고자 할때 그때 SELECT문을 날려서 정보를 충당하는 방식. 즉, 그때그때 필요한 정보만 가져오는 것입니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" ? "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("SQLAlchemy ORM의 기본 컬렉션 및 관련 특성은 "),a("strong",[s._v("lazy loading")]),s._v(" 입니다. 즉, 한번 "),a("code",[s._v("relationship")]),s._v(" 된 컬렉션은 데이터가 메모리에 존재하는 한 계속 접근을 사용할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("p",[s._v("lazy loading은 최적화를 위한 명시적인 단계를 수행하지 않으면 비용이 많이 들 수 있지만, 적어도 lazy loading은 중복 작업을 수행하지 않도록 최적화되어 있습니다.")]),s._v(" "),a("p",[a("code",[s._v("u1.addresses")]),s._v("의 컬렉션에 "),a("code",[s._v("a1")]),s._v(" 및 "),a("code",[s._v("a2")]),s._v(" 객체들 또한 볼 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a1\nAddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" a2\nAddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" email_address"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[a("code",[s._v("relationship")]),s._v(" 개념에 대한 추가 소개는 이 섹션의 후반부에 더 설명드리겠습니다.")]),s._v(" "),a("br"),s._v(" "),a("h2",{attrs:{id:"쿼리에서-relationship-사용하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#쿼리에서-relationship-사용하기"}},[s._v("#")]),s._v(" 쿼리에서 "),a("code",[s._v("relationship")]),s._v(" 사용하기")]),s._v(" "),a("br"),s._v(" "),a("p",[s._v("이 섹션에서는 "),a("code",[s._v("relationship()")]),s._v(" 이 SQL 쿼리 구성을 자동화하는데 도움이 되는 여러 가지 방법을 소개합니다.")]),s._v(" "),a("br"),s._v(" "),a("h3",{attrs:{id:"relationship-을-사용하여-조인하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#relationship-을-사용하여-조인하기"}},[s._v("#")]),s._v(" "),a("code",[s._v("relationship()")]),s._v("을 사용하여 조인하기")]),s._v(" "),a("p",[a("RouterLink",{attrs:{to:"/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#from절과-join-명시하기)"}},[s._v("FROM절과 JOIN명시하기")]),s._v(" 및 "),a("RouterLink",{attrs:{to:"/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#where절)"}},[s._v("WHERE절")]),s._v(" 섹션에서는 "),a("code",[s._v("Select.join()")]),s._v(" 및 "),a("code",[s._v("Select.join_from()")]),s._v(" 메서드를 사용하여 SQL JOIN을 구성하였습니다."),a("br"),s._v("\n테이블간에 조인하는 방법을 설명하기 위해 이러한 메서드는 두 테이블을 연결하는 "),a("code",[s._v("ForeignKeyConstraint")]),s._v(" 객체가 있는지 여부에 따라 ON 절을 유추하거나 특정 ON 절을 나타내는 SQL Expression 구문을 제공 할 수 있습니다.")],1),s._v(" "),a("p",[a("code",[s._v("relationship()")]),s._v(" 객체를 사용하여 join의 ON 절을 설정할 수 있습니다.\n"),a("code",[s._v("relationship()")]),s._v(" 에 해당하는 객체는 "),a("code",[s._v("Select.join()")]),s._v("의 "),a("strong",[s._v("단일 인수")]),s._v("로 전달될 수 있으며,\nright join과 ON 절을 동시에 나타내는 역할을 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n")])])]),a("p",[s._v("매핑된 "),a("code",[s._v("relationship()")]),s._v("있는 경우 "),a("code",[s._v("Select.join()")]),s._v(" 또는 "),a("code",[s._v("Select.join_from()")]),s._v(" 지정하지 않을 경우 "),a("strong",[s._v("ON 절은 사용되지 않습니다.")]),a("br"),s._v("\n즉, "),a("code",[s._v("user")]),s._v(" 및 "),a("code",[s._v("Address")]),s._v(" 객체의 "),a("code",[s._v("relationship()")]),s._v(" 객체가 아니라 매핑된 두 테이블 객체 간의 "),a("code",[s._v("ForeignKeyConstraint")]),s._v("로 인해 작동합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n")])])]),a("br"),s._v(" "),a("h3",{attrs:{id:"별칭-aliased-을-사용하여-조인하기"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#별칭-aliased-을-사용하여-조인하기"}},[s._v("#")]),s._v(" 별칭(aliased)을 사용하여 조인하기")]),s._v(" "),a("p",[a("code",[s._v("relationship()")]),s._v("을 사용하여 SQL JOIN을 구성하는 경우 ["),a("code",[s._v("PropComparator.of_type()")]),s._v("] 사용하여 조인 대상이 "),a("code",[s._v("aliased()")]),s._v("이 되는 사용 사례가 적합합니다. 그러나 "),a("code",[s._v("relationship()")]),s._v("를 사용하여 ["),a("code",[s._v("ORM Entity Aliases")]),s._v("]에 설명된 것과 동일한 조인을 구성합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" aliased\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" address_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" address_alias_2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("address_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'patrick@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join_from"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("address_alias_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'patrick@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_2 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" address_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" :email_address_1\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("AND")]),s._v(" address_2"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" :email_address_2\n")])])]),a("p",[a("code",[s._v("relationship()")]),s._v("을 사용하여 "),a("code",[s._v("aliased()")]),s._v("에서 조인을 직접 사용할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" user_alias_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" aliased"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("user_alias_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_1\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n")])])]),a("br"),s._v(" "),a("h3",{attrs:{id:"on-조건-확대"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#on-조건-확대"}},[s._v("#")]),s._v(" ON 조건 확대")]),s._v(" "),a("p",[a("code",[s._v("relation()")]),s._v("으로 생성된 ON 절에 조건을 추가할 수 있습니다. 이 기능은 관계된 경로에 대한 특정 조인의 범위를 신속하게 제한하는 방법뿐만 아니라 마지막 섹션에서 소개하는 로더 전략 구성과 같은 사용 사례에도 유용합니다."),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/internals.html#sqlalchemy.orm.PropComparator.and_)"}},[a("code",[s._v("PropComparator.and_()")])]),s._v(" 메서드는 AND를 통해 JOIN의 ON 절에 결합되는 일련의 SQL 식을 위치적으로 허용합니다. 예를 들어,"),a("br"),s._v(" "),a("code",[s._v("User")]),s._v(" 및 "),a("code",[s._v("Address")]),s._v("을 활용하여 ON 기준을 특정 이메일 주소로만 제한하려는 경우 이와 같습니다.")],1),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("AND")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" ?\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("br"),s._v(" "),a("h3",{attrs:{id:"exists-has-and"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#exists-has-and"}},[s._v("#")]),s._v(" EXISTS has() , and()")]),s._v(" "),a("p",[a("RouterLink",{attrs:{to:"/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#exists-서브쿼리들)"}},[s._v("EXISTS 서브쿼리들")]),s._v(" 섹션에서는 SQL EXISTS 키워드를 "),a("RouterLink",{attrs:{to:"/tutorial/(https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5. 데이터 핸들링 - Core, ORM으로 행 조회하기.html#스칼라-서브-쿼리-상호연관-쿼리)"}},[s._v("스칼라 서브 쿼리, 상호연관 쿼리")]),s._v(" 섹션과 함께 소개했습니다."),a("br"),s._v(" "),a("code",[s._v("relationship()")]),s._v(" 은 관계 측면에서 공통적으로 서브쿼리를 생성하는데 사용할 수 있는 일부 도움을 제공합니다.")],1),s._v(" "),a("br"),s._v(" "),a("p",[a("code",[s._v("User.addresses")]),s._v("와 같은 1:N (one-to-many) 관계의 경우 "),a("code",[s._v("PropComparator.any()")]),s._v("를 사용하여 "),a("code",[s._v("user_account")]),s._v("테이블과 다시 연결되는 주소 테이블에 서브쿼리를 생성할 수 있습니다. 이 메서드는 하위 쿼리와 일치하는 행을 제한하는 선택적 WHERE 기준을 허용합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Pearl Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("EXISTS")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("AND")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("이와 반대로 관련된 데이터가 없는 객체를 찾는 것은 "),a("code",[s._v("~User.addresses.any()")]),s._v("을 사용하여 "),a("code",[s._v("User")]),s._v(" 객체에 검색하는 방법입니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("~")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Patrick McStar'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Squidward Tentacles'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Eugene H. Krabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("NOT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("EXISTS")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n")])])]),a("p",[a("code",[s._v("PropComparator.has()")]),s._v(" 메서드는 "),a("code",[s._v("PropComparator.any()")]),s._v("와 비슷한 방식으로 작동하지만, N:1 (Many-to-one) 관계에 사용됩니다."),a("br"),s._v('\n예시로 "pearl"에 속하는 모든 '),a("code",[s._v("Address")]),s._v(" 객체를 찾으려는 경우 이와 같습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("has"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"pkrabs"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("all")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl.krabs@gmail.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pearl@aol.com'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("EXISTS")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("AND")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("br"),s._v(" "),a("h3",{attrs:{id:"관계-연산자"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#관계-연산자"}},[s._v("#")]),s._v(" 관계 연산자")]),s._v(" "),a("p",[a("code",[s._v("relationship()")]),s._v("와 함께 제공되는 SQL 생성 도우미에는 다음과 같은 몇 가지 종류가 있습니다.")]),s._v(" "),a("ul",[a("li",[s._v("N : 1 (Many-to-one) 비교"),a("br"),s._v("\n특정 객체 인스턴스를 N : 1 관계와 비교하여 대상 엔티티의 외부 키가 지정된 객체의 기본 키값과 일치하는 행을 선택할 수 있습니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" :param_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n")])])]),a("ul",[a("li",[s._v("NOT N : 1 (Many-to-one) 비교"),a("br"),s._v("\n같지 않은 연산자(!=)를 사용할 수 있습니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!=")]),s._v(" u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!=")]),s._v(" :user_id_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("OR")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("IS")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("NULL")]),s._v("\n")])])]),a("ul",[a("li",[s._v("객체가 1 : N (one-to-many) 컬렉션에 포함되어있는지 확인하는 방법입니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("contains"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("a1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" :param_1\n")])])]),a("ul",[a("li",[s._v("객체가 1 : N 관계에서 특정 상위 항목에 있는지 확인하는 방법입니다."),a("br"),s._v(" "),a("code",[s._v("with_parent()")]),s._v("은 주어진 상위 항목이 참조하는 행을 반환하는 비교를 생성합니다. 이는 == 연산자를 사용하는 것과 동일합니다.")])]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" with_parent\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("with_parent"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("u1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" :param_1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n")])])]),a("br"),s._v(" "),a("h2",{attrs:{id:"loading-relationshiop의-종류"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#loading-relationshiop의-종류"}},[s._v("#")]),s._v(" Loading relationshiop의 종류")]),s._v(" "),a("br"),s._v(" "),a("p",[a("a",{attrs:{href:"#%EA%B4%80%EA%B3%84-%EB%A1%9C%EB%93%9C"}},[a("code",[s._v("관계 로드")])]),s._v(" 섹션에서는 매핑된 객체 인스턴스로 작업할 때 "),a("code",[s._v("relationship()")]),s._v("을 사용하여 매핑된 특성에 엑세스하면 이 컬렉션에 있어야 하는 객체를 로드하며, 컬렉션이 채워지지 않은 경우 "),a("code",[s._v("lazy load")]),s._v("가 발생한다는 개념을 도입했습니다.")]),s._v(" "),a("p",[s._v("Lazy loading 방식은 가장 유명한 ORM 패턴 중 하나이며, 가장 논란이 많은 ORM 패턴이기도 합니다."),a("br"),s._v("\n메모리에 있는 수십개의 ORM 객체가 각각 소수의 언로드 속성을 참조하는 경우, 객체의 일상적인 조작은 누적이 될 수 있는 많은 문제("),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/glossary.html#term-N-plus-one-problem)"}},[a("code",[s._v("N+1 Problem")])]),s._v(")를 암묵적으로 방출될 수 있습니다. 이러한 암시적 쿼리는 더 이상 사용할 수 없는 데이터베이스 변환을 시도할 때 또는 비동기화 같은 대체 동시성 패턴을 사용할 때 실제로 전혀 작동하지 않을 수 있습니다.")],1),s._v(" "),a("blockquote",[a("p",[a("a",{attrs:{href:"(https://blog.naver.com/yysdntjq/222405755893)"}},[a("code",[s._v("N + 1 Problem")])]),s._v("이란?"),a("br"),s._v("\n쿼리 1번으로 N건의 데이터를 가져왔는데 원하는 데이터를 얻기 위해 이 N건의 데이터를 데이터 수 만큼 반복해서 2차적으로 쿼리를 수행하는 문제입니다.")])]),s._v(" "),a("p",[s._v("lazy loading 방식은 사용 중인 동시성 접근법과 호환되고 다른 방법으로 문제를 일으키지 않을 때 매우 인기있고 유용한 패턴입니다. 이러한 이유로 SQLAlchemy의 ORM은 이러한 로드 동작을 제허하고 최적화할 수 있는 기능에 중점을 둡니다.")]),s._v(" "),a("p",[s._v("무엇보다 ORM의 lazy loading 방식을 효과적으로 사용하는 첫 번째 단계는 "),a("strong",[s._v("Application을 테스트하고 SQL을 확인하는 것입니다.")]),a("br"),s._v(" "),a("code",[s._v("Session")]),s._v("에서 분리된 객체에 대해 로드가 부적절하게 발생하는 경우, "),a("strong",[a("a",{attrs:{href:"#loading-relationshiop%EC%9D%98-%EC%A2%85%EB%A5%98"}},[a("code",[s._v("Loading relationship의 종류")])])]),s._v(" 사용을 검토해야 합니다.")]),s._v(" "),a("p",[a("code",[s._v("Select.options()")]),s._v(" 메서드를 사용하여 SELECT 문과 연결할 수 있는 객체로 표시됩니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user_obj "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n user_obj"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# access addresses collection already loaded")]),s._v("\n")])])]),a("p",[a("code",[s._v("relationship.lazy")]),s._v("를 사용하여 "),a("code",[s._v("relationship()")]),s._v("의 기본값으로 구성할 수도 있습니다.")]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" relationship\nclass "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(":\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'user_account'")]),s._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"selectin"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("가장 많이 사용되는 loading 방식 몇 가지를 소개합니다.")]),s._v(" "),a("blockquote",[a("p",[s._v("참고"),a("br"),s._v(" "),a("strong",[s._v("관계 로딩 기법의 2가지 기법")]),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#relationship-lazy-option)"}},[a("code",[s._v("Configuring Loader Strategies at Mapping Time")])]),s._v(" - "),a("code",[s._v("relationship()")]),s._v(" 구성에 대한 세부정보"),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#relationship-loader-options)"}},[a("code",[s._v("Relationship Loading with Loader Options")])]),s._v(" - 로더에 대한 세부정보")],1)]),s._v(" "),a("br"),s._v(" "),a("h3",{attrs:{id:"select-in-loading-방식"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#select-in-loading-방식"}},[s._v("#")]),s._v(" Select IN loading 방식")]),s._v(" "),a("p",[s._v("최신 SQLAlchemy에서 가장 유용한 로딩방식 옵션은 "),a("code",[s._v("selectinload()")]),s._v('입니다. 이 옵션은 관련 컬렉션을 참조하는 객체 집합의 문제인 가장 일반적인 형태의 "N + 1 Problem"문제를 해결합니다.'),a("br"),s._v("\n대부분의 경우 JOIN 또는 하위 쿼리를 도입하지 않고 관련 테이블에 대해서만 내보낼 수 있는 SELET 양식을 사용하여 이 작업을 수행합니다. 또한 컬렉션이 로드되지 않은 상위 객체에 대한 쿼리만 수행합니다."),a("br"),s._v("\n아래 예시는 "),a("code",[s._v("User")]),s._v(" 객체와 관련된 "),a("code",[s._v("Address")]),s._v(" 객체를 "),a("code",[s._v("selectinload()")]),s._v("하여 보여줍니다."),a("br"),s._v(" "),a("code",[s._v("Session.execute()")]),s._v(" 호출하는 동안 데이터베이스에서는 두 개의 SELECT 문이 생성되고 두 번째는 관련 "),a("code",[s._v("Address")]),s._v(" 객체를 가져오는 것입니다.")]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" selectinload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("select")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("row")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("in")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("session")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("execute")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(":\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("f"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("\"{row.User.name} ({', '.join(a.email_address for a in row.User.addresses)})\"")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nspongebob "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("spongebob"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("@sqlalchemy.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nsandy "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("sandy"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("@sqlalchemy.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" sandy"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("@squirrelpower.org")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\npatrick "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nsquidward "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nehkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\npkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("pearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("krabs"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("@gmail.com")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" pearl"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("@aol.com")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ORDER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BY")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("IN")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("br"),s._v(" "),a("h3",{attrs:{id:"joined-loading-방식"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#joined-loading-방식"}},[s._v("#")]),s._v(" Joined Loading 방식")]),s._v(" "),a("p",[a("code",[s._v("Joined Loading")]),s._v("은 SQLAlchemy에서 가장 오래됬으며, 이 방식은 eager loading의 일종으로 "),a("code",[s._v("joined eager loading")]),s._v("이라고도 합니다. N : 1 관계의 객체를 로드하는 데 가장 적합하며,\n"),a("code",[s._v("relationship()")]),s._v("에 명시된 테이블을 SELECT JOIN하여 모든 테이블의 데이터들을 한꺼번에 가져오는 방식으로 "),a("code",[s._v("Address")]),s._v(" 객체에 연결된 사용자가 있는 다음과 같은 경우에 OUTER JOIN이 아닌 INNER JOIN을 사용할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" joinedload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("joinedload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" innerjoin"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[s._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\nspongebob@sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("org spongebob\nsandy@sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("org sandy\nsandy@squirrelpower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("org sandy\npearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com pkrabs\npearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com pkrabs\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\nuser_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ORDER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BY")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[a("code",[s._v("joinedload()")]),s._v("는 1 : N 관계를 의미하는 컬렉션에도 사용되지만 중접 컬렉션 및 더 큰 컬렉션이므로 "),a("code",[s._v("selectinload()")]),s._v(" 처럼 사례별로 평가해야 하는 것과 같은 다른 옵션과 비교 합니다.")]),s._v(" "),a("p",[s._v("SELECT 쿼리문의 WHERE 및 ORDER BY 기준은 "),a("strong",[s._v("joinload()에 의해 렌더링된 테이블을 대상으로 하지 않는다는")]),s._v(" 점에 유의하는 것이 중요합니다. 위 SQL 쿼리에서 직접 주소를 지정할 수 없는 *익명 별칭**이 "),a("code",[s._v("user_account")]),s._v("테이블에 적용된 것을 볼 수 있습니다. 이 개념은 "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#zen-of-eager-loading)"}},[a("code",[s._v("Zen of joined Eager Loading")])]),s._v(" 섹션에서 더 자세히 설명합니다.")],1),s._v(" "),a("p",[a("code",[s._v("joinedload()")]),s._v("에 의해 ON 절은 이전 "),a("a",{attrs:{href:"#on-%EC%A1%B0%EA%B1%B4-%ED%99%95%EB%8C%80"}},[a("code",[s._v("ON 조건 확대")])]),s._v("에서 설명한 방법 "),a("code",[s._v("joinedload()")]),s._v("을 사용하여 직접 영향을 받을 수 있습니다.")]),s._v(" "),a("blockquote",[a("p",[s._v("참고"),a("br"),s._v('\n일반적인 경우에는 "N + 1 problem"가 훨씬 덜 만연하기 때문에 다대일 열망 로드가 종종 필요하지 않다는 점에 유의하는 것이 중요합니다. 많은 객체가 모두 동일한 관련 객체를 참조하는 경우(예: '),a("code",[s._v("Address")]),s._v(" 각각 동일한 참조하는 많은 객체) 일반 지연 로드를 사용하여 "),a("code",[s._v("User")]),s._v("객체에 대해 SQL이 한 번만 내보내 집니다. 지연 로드 루틴은 "),a("code",[s._v("Session")]),s._v("가능한 경우 SQL을 내보내지 않고 현재 기본 키로 관련 객체를 조회 합니다.")])]),s._v(" "),a("br"),s._v(" "),a("h3",{attrs:{id:"explicit-join-eager-load-방식"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#explicit-join-eager-load-방식"}},[s._v("#")]),s._v(" Explicit Join + Eager load 방식")]),s._v(" "),a("p",[s._v("일반적인 사용 사례는 "),a("code",[s._v("contains_eager()")]),s._v("옵션을 사용하며, 이 옵션은 JOIN을 직접 설정했다고 가정하고 대신 COLUMNS 절의 추가 열이 반환된 각 객체의 관련 속성에 로드해야 한다는 점을 제외하고는 "),a("code",[s._v("joinedload()")]),s._v(" 와 매우 유사합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" contains_eager\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("contains_eager"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[s._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v(" ")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\npearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com pkrabs\npearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com pkrabs\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" ? "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ORDER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BY")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("위에서 "),a("code",[s._v("user_account.name")]),s._v("을 필터링하고 "),a("code",[s._v("user_account")]),s._v("의 반환된 "),a("code",[s._v("Address.user")]),s._v("속성으로 로드했습니다."),a("br"),s._v(" "),a("code",[s._v("joinedload()")]),s._v("를 별도로 적용했다면 불필요하게 두 번 조인된 SQL 쿼리가 생성되었을 것입니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" where"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'pkrabs'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("joinedload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# SELECT has a JOIN and LEFT OUTER JOIN unnecessarily")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\nuser_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" id_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("LEFT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("OUTER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("JOIN")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" user_account_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ON")]),s._v(" user_account_1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" :name_1 "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ORDER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BY")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id\n")])])]),a("br"),s._v(" "),a("blockquote",[a("p",[s._v("참고"),a("br"),s._v(" "),a("strong",[s._v("관계 로딩 기법의 2가지 기법")]),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#zen-of-eager-loading)"}},[a("code",[s._v("Zen of joined Eager Loading")])]),s._v(" - 해당 로딩 방식에 대한 세부정보"),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#contains-eager)"}},[a("code",[s._v("Routing Explicit Joins/Statements into Eagerly Loaded Collections")])]),s._v(" - using "),a("code",[s._v("contains_eager()")])],1)]),s._v(" "),a("br"),s._v(" "),a("h3",{attrs:{id:"로더-경로-설정"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#로더-경로-설정"}},[s._v("#")]),s._v(" 로더 경로 설정")]),s._v(" "),a("p",[a("code",[s._v("PropComparator.and_()")]),s._v(" 방법은 실제로 대부분의 로더 옵션에서 일반적으로 사용할 수 있습니다.\n예를 들어 "),a("code",[s._v("sqlalchemy.org")]),s._v("도메인에서 사용자 이름과 이메일 주소를 다시 로드하려는 경우 "),a("code",[s._v("selectinload()")]),s._v(" 전달된 인수에 "),a("code",[s._v("PropComparator.and_()")]),s._v("를 적용하여 다음 조건을 제한할 수 있습니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" sqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("orm "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" selectinload\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" stmt "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("and_"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("~")]),s._v("Address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("endswith"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"sqlalchemy.org"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" order_by"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" execution_options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("populate_existing"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[s._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" row "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" session"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("stmt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[s._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v(" (")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("', '")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("join"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("a"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" a "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" row"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v(')"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\nspongebob "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nsandy "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("sandy@squirrelpower"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("org"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\npatrick "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nsquidward "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nehkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\npkrabs "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("pearl"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("krabs@gmail"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" pearl@aol"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("com"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("blockquote",[a("p",[s._v("위 코드는 다음 쿼리를 실행하는 것과 같습니다.")])]),s._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("fullname\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" user_account "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("ORDER")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("BY")]),s._v(" user_account"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("SELECT")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_user_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("id "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\naddress"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("AS")]),s._v(" address_email_address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("FROM")]),s._v(" address\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("WHERE")]),s._v(" address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("user_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("IN")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("AND")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("address"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("email_address "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("NOT")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("LIKE")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'%'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("||")]),s._v(" ?"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'sqlalchemy.org'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("위에서 매우 중요한 점은 "),a("code",[s._v(".execution_options(populate_existing=True)")]),s._v(" 옵션이 추가되었다는 점 입니다."),a("br"),s._v("\n행을 가져올 때 적용되는 이 옵션은 로더 옵션이 이미 로드된 객체의 기존 컬렉션 내용을 대체해야 함을 나타냅니다."),a("br"),s._v(" "),a("code",[s._v("Session")]),s._v("객체로 반복 작업하므로 위에서 로드되는 객체는 본 튜토리얼의 ORM 섹션 시작 시 처음 유지되었던 것과 동일한 Python 인스턴스입니다.")]),s._v(" "),a("br"),s._v(" "),a("h3",{attrs:{id:"raise-loading-방식"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#raise-loading-방식"}},[s._v("#")]),s._v(" raise loading 방식")]),s._v(" "),a("p",[a("code",[s._v("raiseload()")]),s._v("옵션은 일반적으로 느린 대신 오류를 발생시켜 N + 1 문제가 발생하는 것을 완전히 차단하는데 사용됩니다."),a("br"),s._v("\n예로 두 가지 변형 모델이 있습니다. SQL이 필요한 "),a("code",[s._v("lazy load")]),s._v(" 와 현재 "),a("code",[s._v("Session")]),s._v('만 참조하면 되는 작업을 포함한 모든 "load" 작업을 차단하는 '),a("code",[s._v("raiseload.sql_only")]),s._v(" 옵션입니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("User")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'user_account'")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ... Column mappings")]),s._v("\n\n addresses "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Address"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"user"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"raise_on_sql"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Address")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Base"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n __tablename__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'address'")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ... Column mappings")]),s._v("\n\n user "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" relationship"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"User"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" back_populates"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"addresses"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"raise_on_sql"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[s._v("이러한 매핑을 사용하면 응용 프로그램이 'lazy loading'에 차단되어 특정 쿼리에 로더 전략을 지정해야 합니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[s._v("u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\nu1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses\nsqlalchemy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("exc"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("InvalidRequestError"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'User.addresses'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("is")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("not")]),s._v(" available due to lazy"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'raise_on_sql'")]),s._v("\n")])])]),a("p",[s._v("예외는 이 컬렉션을 대신 먼저 로드해야 함을 나타냅니다.")]),s._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[s._v("u1 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("execute"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("select"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("options"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("selectinload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("User"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("addresses"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("scalars"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("first"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("p",[a("code",[s._v('lazy="raise_on_sql"')]),s._v(" 옵션은 N : 1 관계에도 현명하게 시도합니다."),a("br"),s._v("\n위에서 "),a("code",[s._v("Address.user")]),s._v("속성이 "),a("code",[s._v("Address")]),s._v("에 로드되지 않았지만 해당 "),a("code",[s._v("User")]),s._v(" 객체가 동일한 "),a("code",[s._v("Session")]),s._v('에 있는 경우 "raiseload"은 오류를 발생시키지 않습니다.')]),s._v(" "),a("blockquote",[a("p",[s._v("참고"),a("br"),s._v(" "),a("RouterLink",{attrs:{to:"/tutorial/(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#prevent-lazy-with-raiseload)"}},[a("code",[s._v("raiseload")]),s._v("를 사용하여 원치 않는 lazy loading 방지")]),a("br"),s._v(" "),a("a",{attrs:{href:"(https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html)"}},[a("code",[s._v("relatonship")]),s._v("에서 lazy loading 방지")])],1)])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/31.363734c1.js b/assets/js/31.363734c1.js new file mode 100644 index 0000000..951388a --- /dev/null +++ b/assets/js/31.363734c1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{427:function(t,o,r){"use strict";r.r(o);var n=r(56),s=Object(n.a)({},(function(){var t=this,o=t.$createElement,r=t._self._c||o;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"tutorial"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#tutorial"}},[t._v("#")]),t._v(" Tutorial")]),t._v(" "),r("p",[t._v("이 문서는 "),r("a",{attrs:{href:"https://docs.sqlalchemy.org/en/14/tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("SQLAlchemy 1.4/2.0 Tutorial"),r("OutboundLink")],1),t._v("를 번역 및 정리한 글입니다.")]),t._v(" "),r("p",[t._v("기존 공식 문서는 보기 어렵고, 너무 많은 내용이 담겨있습니다. 또한 초보자가 보기에 너무 어렵다는 생각이 들었습니다."),r("br"),t._v("\n이에 SQLAlchemy Tutorial 문서를 같이 공부할 겸, 누구나 쉽게 볼 수 있고 정리하면 어떨까라는 생각으로 "),r("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/issues/2",target:"_blank",rel:"noopener noreferrer"}},[t._v("이 글"),r("OutboundLink")],1),t._v("에서 같이 작업할 사람들이 모이게 되었습니다.")]),t._v(" "),r("p",[t._v("한 달이 조금 넘는 기간동안, 매주 돌아가며 공식 Tutorial 문서를 한 챕터씩 맡아서 작업했습니다."),r("br"),t._v("\n서로 리뷰해주며 글을 다듬고, 이해가 안가는 부분을 서로 물어보기도 했습니다."),r("br"),t._v("\n이 문서 모음들은 이러한 과정 끝에 나온 결과물입니다. 저희가 스터디한 흔적이기도 합니다.")]),t._v(" "),r("p",[t._v("여전히 부족한 부분이 많고, 틀린 부분이 있을 수 있습니다."),r("br"),t._v("\n이런 부분 발견하시면 언제든 기여해주세요. 늘 환영하고 있습니다.")]),t._v(" "),r("p",[t._v("아래와 같은 분들이 참여해주셨습니다.")]),t._v(" "),r("a",{attrs:{href:"https://github.com/SoogoonSoogoonPythonists/sqlalchemy-for-pythonist/graphs/contributors"}},[r("img",{attrs:{src:"https://contrib.rocks/image?repo=SoogoonSoogoonPythonists/sqlalchemy-for-pythonist"}})])])}),[],!1,null,null,null);o.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/4.51c0545f.js b/assets/js/4.51c0545f.js new file mode 100644 index 0000000..4725e42 --- /dev/null +++ b/assets/js/4.51c0545f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{371:function(t,e,a){},398:function(t,e,a){"use strict";a(371)},404:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(398),a(56)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/5.220df36c.js b/assets/js/5.220df36c.js new file mode 100644 index 0000000..784473d --- /dev/null +++ b/assets/js/5.220df36c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{372:function(e,t,a){},399:function(e,t,a){"use strict";a(372)},405:function(e,t,a){"use strict";a.r(t);a(84),a(39),a(7),a(116),a(117);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(399),a(56)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/6.345e52dd.js b/assets/js/6.345e52dd.js new file mode 100644 index 0000000..6d70ae3 --- /dev/null +++ b/assets/js/6.345e52dd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{401:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(56),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/assets/js/7.a15a95f4.js b/assets/js/7.a15a95f4.js new file mode 100644 index 0000000..996fb98 --- /dev/null +++ b/assets/js/7.a15a95f4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{403:function(t,s,n){"use strict";n.r(s);var e={data:function(){return{msg:"Hello this is "}}},i=n(56),a=Object(i.a)(e,(function(){var t=this.$createElement;return(this._self._c||t)("p",{staticClass:"demo"},[this._v("\n "+this._s(this.msg)+"\n")])}),[],!1,null,null,null);s.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/8.006f2d84.js b/assets/js/8.006f2d84.js new file mode 100644 index 0000000..566dd0e --- /dev/null +++ b/assets/js/8.006f2d84.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{428:function(t,n,e){"use strict";e.r(n);var s=e(56),i=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("p",{staticClass:"demo"},[this._v("This is another component")])}),[],!1,null,null,null);n.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/9.7948c093.js b/assets/js/9.7948c093.js new file mode 100644 index 0000000..93c3c6c --- /dev/null +++ b/assets/js/9.7948c093.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{402:function(t,n,s){"use strict";s.r(n);var e={data:function(){return{msg:"Hello this is "}}},i=s(56),o=Object(i.a)(e,(function(){var t=this.$createElement;return(this._self._c||t)("p",{staticClass:"demo"},[this._v("\n "+this._s(this.msg)+"\n")])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/app.8473826e.js b/assets/js/app.8473826e.js new file mode 100644 index 0000000..c9dffb5 --- /dev/null +++ b/assets/js/app.8473826e.js @@ -0,0 +1,15 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,u=e[0],s=e[1],c=e[2],f=0,p=[];f=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(160),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(2),o=r({}.toString),i=r("".slice);t.exports=function(t){return i(o(t),8,-1)}},function(t,e,n){var r,o=n(8),i=n(126),a=n(95),u=n(45),s=n(130),c=n(62),l=n(67),f=l("IE_PROTO"),p=function(){},h=function(t){return" + + + + + + + + + + + +
hero

+ SQLAlchemy for Python Developers +

+ This is a document that simplifies SQLAlchemy for easy understanding. +

+ Tutorial → +

+ + + diff --git a/en/tutorial/1. Tutorial Overview.html b/en/tutorial/1. Tutorial Overview.html new file mode 100644 index 0000000..1abb1a4 --- /dev/null +++ b/en/tutorial/1. Tutorial Overview.html @@ -0,0 +1,45 @@ + + + + + + Tutorial Overview | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Tutorial Overview


# Overview

SQLAlchemy is a library in Python that facilitates the connection to databases and the use of ORM (Object-Relational Mapping).
+For instance, you can execute specific queries in your code and perform a series of operations in the database through ORM objects.


# Installation

SQLAlchemy can be installed as follows:

$ pip install sqlalchemy
+

The version being used is as follows:

>>> import sqlalchemy
+>>> sqlalchemy.__version__  
+1.4.20
+

# Offerings

SQLAlchemy is offered in the following two ways:

  • Core
    • This is the database toolkit and the foundational architecture of SQLAlchemy.
    • It manages connections to databases, interacts with database queries and results, and provides tools to programmatically compose SQL statements.
  • ORM
    • Built on top of Core, it provides optional ORM (Object-Relational Mapping) features.

It is generally recommended to understand Core first before using ORM.
+This tutorial will start by explaining Core.

+ + + diff --git a/en/tutorial/2. Setting Up a Connection.html b/en/tutorial/2. Setting Up a Connection.html new file mode 100644 index 0000000..f265772 --- /dev/null +++ b/en/tutorial/2. Setting Up a Connection.html @@ -0,0 +1,50 @@ + + + + + + Setting up a Connection | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Setting up a Connection


# Connecting to a Database

Let's try connecting to SQLite, a relatively lightweight database.
+You can do it as follows:

>>> from sqlalchemy import create_engine
+>>> engine = create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True)
+
  • Use the sqlalchemy.create_engine function to create an 'engine' that establishes a connection to the database.
  • The first argument is a string URL. +
    • Typically, the string URL is structured as dialect+driver://username:password@host:port/database. +
      • If you don't specify a driver, SQLAlchemy's default settings will be used.
    • Here, sqlite+pysqlite:///test.db is the string URL. +
      • For sqlite, the format follows sqlite://<nohostname>/<path>.
  • From the string URL sqlite:///test.db, we can understand the following information: +
    • Which database to use (dialect, in this case, sqlite)
    • Which database API (the driver interacting with the database) to use (in this case, pysqlite)
    • How to find the database (in this case, it uses the in-memory feature provided by sqlite)
  • Setting the echo parameter to True prints all executed SQL.

Creating an engine doesn't yet attempt an actual connection. The real connection occurs only when a request to perform an operation on the database is received for the first time.

+ + + diff --git a/en/tutorial/3. Executing Transactions and Queries.html b/en/tutorial/3. Executing Transactions and Queries.html new file mode 100644 index 0000000..0061820 --- /dev/null +++ b/en/tutorial/3. Executing Transactions and Queries.html @@ -0,0 +1,146 @@ + + + + + + Executing Transactions and Queries | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Executing Transactions and Queries


# Obtaining connection

You can connect to the database and execute a query as follows.

>>> from sqlalchemy import text
+
+>>> with engine.connect() as conn:
+...     result = conn.execute(text("select 'hello world'"))
+...     print(result.all())
+
+[('hello world',)]
+
  • Obtain a Connection (opens new window) object through engine.connect() and store it in conn. +
    • This Connection object allows you to interact with the database.
    • The with statement becomes a single transaction unit.
  • Transactions are not committed automatically.
    • You have to invoke the Connection.commit() to commit changes.

# Committing Changes

Obtaining a connection, initiating a transaction, and interacting with the database do not automatically commit changes.

To commit the change, you need to call Connection.commit() as follows.

>>> with engine.connect() as conn:
+...     # DDL - Creating the table
+...     conn.execute(text("CREATE TABLE some_table (x int, y int)")) 
+...     # DML - Inserting data into the table
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 1, "y": 1}, {"x": 2, "y": 4}]
+...     )
+...     # TCL - Commiting changes.
+...     conn.commit()
+

When you run the code above, you'll see the following result below.

BEGIN (implicit)
+CREATE TABLE some_table (x int, y int)
+[...] ()
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+INSERT INTO some_table (x, y) VALUES (?, ?)
+[...] ((1, 1), (2, 4))
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+COMMIT
+

You can also automatically commit at the end of a transaction using Engine.begin() and with statement.

>>> with engine.begin() as conn:
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 6, "y": 8}, {"x": 9, "y": 10}]
+...     )
+... # Transaction commits automatically when the execution is done.
+

Executing the code above will yield the following results.

BEGIN (implicit)
+INSERT INTO some_table (x, y) VALUES (?, ?)
+[...] ((6, 8), (9, 10))
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+COMMIT
+

# Command Line Execution Basics

You can execute queries and retrieve results as follows.

>>> with engine.connect() as conn:
+...     # conn.execute() initializes the result in an object named `result`.
+...     result = conn.execute(text("SELECT x, y FROM some_table"))
+...     for row in result:
+...         print(f"x: {row.x}  y: {row.y}")
+
+x: 1  y: 1
+x: 2  y: 4
+x: 6  y: 8
+x: 9  y: 10
+
  • The Result (opens new window) object is the object that holds the "query result" returned by conn.execute(). +
    • You can see what features it provides by clicking on the link.
    • For instance, you can receive a list of Row objects using Result.all().

cf. Both Result and Row are objects provided by SQLAlchemy.

You can access each row using the Result object as follows.

result = conn.execute(text("select x, y from some_table"))
+
+# Accessing the tuple.
+for x, y in result:
+    # ...
+    
+# Accessing the value by using integer index.
+for row in result:
+    x = row[0]
+
+# Accessing the value by using a name of the property.
+for row in result:
+    y = row.y
+    
+# Accessing the value by using a mapping access.
+for dict_row in result.mappings():
+    x = dict_row['x']
+    y = dict_row['y']
+

# Passing parameters to your query

You can pass a parameter to a query as follows.

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         text("SELECT x, y FROM some_table WHERE y > :y"),  # Receive in colon format (`:`).
+...         {"y": 2}  # Pass by `dict`.
+...     )
+...     for row in result:
+...        print(f"x: {row.x}  y: {row.y}")
+
+x: 2  y: 4
+x: 6  y: 8
+x: 9  y: 10
+

You can also send multiple parameters like this.

>>> with engine.connect() as conn:
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 11, "y": 12}, {"x": 13, "y": 14}]  # Pass by `List[dict]``
+...     )
+...     conn.commit()
+

The above code executes the following query.

INSERT INTO some_table (x, y) VALUES (?, ?) [...] ((11, 12), (13, 14))
+

# Executing ORM by using Session

From now on, let's execute the query using Session provided by the ORM, instead of the Connection object. +You can do it as follows:

>>> from sqlalchemy.orm import Session
+
+>>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
+
+>>> # Pass an instance of the Engine object to the Session object
+>>> # to get an instance that can interact with the database.
+>>> with Session(engine) as session:
+...     # Executing the query using Session.execute().
+...     result = session.execute(stmt)
+...     for row in result:
+...        print(f"x: {row.x}  y: {row.y}")
+

Like Connection, Session also does not automatically commit upon closing. To commit, you need to explicitly call Session.commit() as follows:

>>> with Session(engine) as session:
+...     result = session.execute(
+...         text("UPDATE some_table SET y=:y WHERE x=:x"),
+...         [{"x": 9, "y":11}, {"x": 13, "y": 15}]
+...     )
+...     # You have to call `commit()` explicitly.
+...     session.commit()
+
+ + + diff --git a/en/tutorial/4. Working with Database Metadata.html b/en/tutorial/4. Working with Database Metadata.html new file mode 100644 index 0000000..67f77f7 --- /dev/null +++ b/en/tutorial/4. Working with Database Metadata.html @@ -0,0 +1,161 @@ + + + + + + Working with Database Metadata | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Working with Database Metadata


SQLAlchemy Core and ORM were created to allow Python objects to be used like tables and columns in a database. These can be used as database metadata.

Metadata describes data that describes other data. Here, metadata refers to configured tables, columns, constraints, and other object information.


# Creating a table object and add it to your metadata

In relational databases, tables are created via queries, but in SQLAlchemy, tables can be created through Python objects. +To start with SQLAlchemy Expression Language, you need to create a Table object for the database table you want to use.

>>> from sqlalchemy import MetaData
+>>> # An object that will hold the meta information for the tables.
+>>> metadata = MetaData()
+>>>
+>>> from sqlalchemy import Table, Column, Integer, String
+>>> user_table = Table(
+...     # The name of the table that will be stored in the database.
+...     'user_account',
+...     metadata,
+...
+...     # The columns that will go into this table.
+...     Column('id', Integer, primary_key=True),
+...     Column('name', String(30)),
+...     Column('fullname', String),
+... )
+
  • You can create database tables using the Table object.

  • Columns of the table are implemented using Column.

    • By default, it defines like Column(column name, data type).
  • After creating a Table instance, you can know the created column information as follows:

>>> user_table.c.name
+Column('name', String(length=30), table=<user_account>)
+
+>>> user_table.c.keys()
+['id', 'name', 'fullname']
+

# Declaring Simple Constraints

We saw the Column('id', Integer, primary_key=True) statement in the code that creates the user table above. This declares the id column as the primary key.

The primary key is implicitly declared as a structure in the PrimaryKeyConstraint object. This can be confirmed as follows.

>>> user_table.primary_key
+PrimaryKeyConstraint(Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False))
+

Along with the primary key, foreign keys can also be declared as follows.

>>> from sqlalchemy import ForeignKey
+>>> address_table = Table(
+...     "address",
+...     metadata,
+...     Column('id', Integer, primary_key=True),
+...     # Declaring Foreign Key as `ForeignKey` object.
+...     Column('user_id', ForeignKey('user_account.id'), nullable=False),
+...     Column('email_address', String, nullable=False)
+... )
+
  • You can declare a foreign key column in the form of ForeignKey('table_name.foreign_key'). +
    • In this case, you can omit the data type of the Column object. The data type is automatically inferred by locating the column corresponding to the foreign key.
  • You can also declare a NOT NULL constraint on a column by passing the nullable=False parameter and value.

# Applying to your database

We have declared database tables using SQLAlchemy so far. Now, let's make these declared tables actually get created in the database.

Execute metadata.create_all() as follows.

>>> metadata.create_all(engine)
+
+# The above code creates all tables recorded in the metadata instance.
+# As a result, it executes the following queries.
+
+BEGIN (implicit)
+PRAGMA main.table_...info("user_account")
+...
+PRAGMA main.table_...info("address")
+...
+CREATE TABLE user_account (
+    id INTEGER NOT NULL,
+    name VARCHAR(30),
+    fullname VARCHAR,
+    PRIMARY KEY (id)
+)
+...
+CREATE TABLE address (
+    id INTEGER NOT NULL,
+    user_id INTEGER NOT NULL,
+    email_address VARCHAR NOT NULL,
+    PRIMARY KEY (id),
+    FOREIGN KEY(user_id) REFERENCES user_account (id)
+)
+...
+COMMIT
+

# Defining table metadata the ORM way

We will create the same database structure and use the same constraints as above, but this time we will proceed using the ORM approach.


# Setting the registry object.

First of all, create a registry object as follows.

>>> from sqlalchemy.orm import registry
+>>> mapper_registry = registry()
+

The registry object contains a MetaData object.

>>> mapper_registry.metadata
+MetaData()
+

Now we can execute the following code.

>>> Base = mapper_registry.generate_base()
+

The above process can be simplified using declarative_base as follows.

>>> from sqlalchemy.orm import declarative_base
+>>> Base = declarative_base()
+

# Declaring the ORM object

By defining a subclass that inherits from the Base object, you can declare tables in the database using the ORM approach.

>>> from sqlalchemy.orm import relationship
+>>> class User(Base):
+...     # A name of the table to be used in the database.
+...     __tablename__ = 'user_account'
+...
+...     id = Column(Integer, primary_key=True)
+...     name = Column(String(30))
+...     fullname = Column(String)
+...
+...     addresses = relationship("Address", back_populates="user")
+...
+...     def __repr__(self):
+...        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"
+
+>>> class Address(Base):
+...     __tablename__ = 'address'
+...
+...     id = Column(Integer, primary_key=True)
+...     email_address = Column(String, nullable=False)
+...     user_id = Column(Integer, ForeignKey('user_account.id'))
+...
+...     user = relationship("User", back_populates="addresses")
+...
+...     def __repr__(self):
+...         return f"Address(id={self.id!r}, email_address={self.email_address!r})"
+

The User and Address objects include a Table object.

You can check this through the __table__ attribute as follows.

>>> User.__table__
+Table('user_account', MetaData(),
+    Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False),
+    Column('name', String(length=30), table=<user_account>),
+    Column('fullname', String(), table=<user_account>), schema=None)
+

# Creating an ORM object

After defining the table, you can create an ORM object as follows.

>>> sandy = User(name="sandy", fullname="Sandy Cheeks")
+>>> sandy
+User(id=None, name='sandy', fullname='Sandy Cheeks')
+

# Applying to your database

Now, you can apply the tables declared with ORM to the actual database as follows.

>>> mapper_registry.metadata.create_all(engine)
+>>> Base.metadata.create_all(engine)
+

# Importing tables from an existing database into an ORM object

Aside from the above methods, there is a way to retrieve tables from the database without declaring them directly.

>>> some_table = Table("some_table", metadata, autoload_with=engine)
+
+BEGIN (implicit)
+PRAGMA main.table_...info("some_table")
+[raw sql] ()
+SELECT sql FROM  (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'
+[raw sql] ('some_table',)
+PRAGMA main.foreign_key_list("some_table")
+...
+PRAGMA main.index_list("some_table")
+...
+ROLLBACK
+

Now it can be used as follows:

>>> some_table
+Table('some_table', MetaData(),
+    Column('x', INTEGER(), table=<some_table>),
+    Column('y', INTEGER(), table=<some_table>),
+    schema=None)
+
+ + + diff --git a/en/tutorial/5.1. Querying Rows Using Core and ORM.html b/en/tutorial/5.1. Querying Rows Using Core and ORM.html new file mode 100644 index 0000000..b8d9dcb --- /dev/null +++ b/en/tutorial/5.1. Querying Rows Using Core and ORM.html @@ -0,0 +1,608 @@ + + + + + + Querying Rows Using Core and ORM | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Querying Rows Using Core and ORM


This chapter covers the most frequently used Select in SQLAlchemy.


# Constructing SQL Expressions with select()

The select() constructor allows you to create query statements in the same way as the insert() constructor.

>>> from sqlalchemy import select
+>>> stmt = select(user_table).where(user_table.c.name == 'spongebob')
+>>> print(stmt)
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1
+"""
+

Similarly, you can put a query in the Connection.execute() method to execute a query statement, just like any SQL constructor at the same level (select, insert, update,create and etc.).

>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         print(row)
+(1, 'spongebob', 'Spongebob Squarepants')
+

On the other hand, if you want to use the ORM to execute a select query statement, you should use Session.exeuct().

The result returns a Row object, just like in the example just now. This object contains the User object that we defined in the previous tutorial (opens new window).

>>> stmt = select(User).where(User.name == 'spongebob')
+>>> with Session(engine) as session:
+...     for row in session.execute(stmt):
+...         # Print each row in an instance of the User object
+...         print(row)
+(User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)
+

# Setting up the FROM clause and columns

The select() function can take a variety of objects as positional arguments, including Column and Table.

These argument values can be represented as the return value of the select() function, i.e., as an SQL query statement, and can also set the FROM clause.

>>> print(select(user_table))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+"""
+

To retrieve each column using the Core, you can access the Column object through the Table.c accessor.

>>> print(select(user_table.c.name, user_table.c.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

# ORM entity and column lookups

When implementing SQL queries in SQLAlchemy, you can use ORM entities like the User object or attributes that map to columns, such as User.name, to represent tables or columns. The example below queries the User entity, but in fact, the result is the same as when using user_table.

The example below looks up the User entity, but the results are the same as when using user_table.

>>> print(select(User))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+"""
+

In the above example, the query can be executed in the same way using ORM's Session.execute().

However, there is a difference between querying the User entity and querying user_info. Whether you query user_info or the User entity, in both cases a Row object is returned.

But, when querying the User entity, the returned Row object includes a User instance.

Tips:

The user_table and User were created in the previous chapter (opens new window), +where user_table is a Table object, and +User is an entity that inherits from the Base object and includes a Table object."

>>> with Session(engine) as session:
+...     row = session.execute(select(User)).first()
+...     print(row)
+(User(id=1, name='spongebob',fullname='Spongebob Squarepants'),)
+

Alternatively, you can query the desired columns using object attributes(class-bound attributes).

>>> print(select(User.name, User.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

When querying object attributes using Session.execute(), the values of the object attributes sent as arguments (column values) are returned as follows.

>>> with Session(engine) as session:
+...	row = session.execute(select(User.name, User.fullname)).first()
+...	print(row)
+('spongebob', 'Spongebob Squarepants')
+

These methods can also be mixed and used together, as shown in the following example

>>> session.execute(
+...     select(User.name, Address).
+...     where(User.id==Address.user_id).
+...     order_by(Address.id)
+... ).all()
+[('spongebob', Address(id=1, email_address='spongebob@sqlalchemy.org')),
+('sandy', Address(id=2, email_address='sandy@sqlalchemy.org')),
+('sandy', Address(id=3, email_address='sandy@squirrelpower.org'))]
+

# Querying Labeled SQL Expressions

When you execute a query like SELECT name AS username FROM user_account, you can get the following results:

username
patrick
sandy
spongebob

Here, we've labeled the name column as username, which is why username appears as the column header. This functionality can be implemented in SQLAlchemy using the ColumnElement.label() function, as shown below:

>>> from sqlalchemy import func, cast
+>>> stmt = (
+...     select(
+...         # Labeling is done like this.
+...         ("Username: " + user_table.c.name).label("username"),
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         # The labeled part can be accessed like this.
+...         print(f"{row.username}")
+Username: patrick
+Username: sandy
+Username: spongebob
+

# Querying String Columns

Usually, columns are queried using the Select object or the select() constructor, but sometimes you need to query a column along with an arbitrary string. This section covers how to query such string data.

The text() constructor was introduced in a previous chapter 3 (opens new window). Transactions and Database API Operations. It allows you to directly use a SELECT statement within it.

Let's consider a scenario where we want to execute a query like SELECT 'some_phrase', name FROM user_account. In this case, since some_phrase is a string, it must be enclosed in either single or double quotes. Consequently, the output will inevitably have single quotes around the string.

>>> from sqlalchemy import text
+>>> stmt = (
+...     select(
+...         text("'some phrase'"), user_table.c.name
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     print(conn.execute(stmt).all())
+[('some phrase', 'patrick'), ('some phrase', 'sandy'), ('some phrase', 'spongebob')]
+

Therefore, instead of text(), it is common to use literal_column() to solve the problem of having single quotes attached to the output. text() and literal_column() are almost similar, but literal_column() explicitly signifies a column and can be labeled for use in subqueries and other SQL expressions."

>>> from sqlalchemy import literal_column
+>>> stmt = (
+...     select(
+...         literal_column("'some phrase'").label("p"), user_table.c.name
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         print(f"{row.p}, {row.name}")
+some phrase, patrick
+some phrase, sandy
+some phrase, spongebob
+
+

# WHERE Clauses

Using SQLAlchemy, you can easily write queries to output data where conditions like name = 'thead' or user_id > 10 are met using Python operators.

>>> print(user_table.c.name == 'squidward')
+user_account.name = :name_1
+
+>>> print(address_table.c.user_id > 10)
+address.user_id > :user_id_1
+

To create a WHERE clause, you can pass arguments to the Select.where() method.

>>> print(select(user_table).where(user_table.c.name == 'squidward'))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1
+"""
+

When implementing a JOIN with a WHERE clause, it can be written as follows.

>>> print(
+...         select(address_table.c.email_address).
+...         where(user_table.c.name == 'squidward').
+...         where(address_table.c.user_id == user_table.c.id)
+... )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE user_account.name = :name_1 AND address.user_id = user_account.id
+"""
+
+# The same expression can be used, but you can also pass parameters to the where() method.
+>>> print(
+        select(address_table.c.email_address).
+...         where(
+...             user_table.c.name == 'squidward',
+...             address_table.c.user_id == user_table.c.id
+...         )
+... )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE user_account.name = :name_1 AND address.user_id = user_account.id
+"""
+

It's also possible to use conjunctions such as and_() and or_().

>>> from sqlalchemy import and_, or_
+>>> print(
+...     select(Address.email_address).
+...         where(
+...             and_(
+...                 or_(User.name == 'squidward', User.name == 'sandy'),
+...                 Address.user_id == User.id
+...             )
+...         )
+...  )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE (user_account.name = :name_1 OR user_account.name = :name_2)
+AND address.user_id = user_account.id
+"""
+

For simple equality or inequality comparisons, Select.filter_by() is often used.

>>> print(
+...     select(User).filter_by(name='spongebob', fullname='Spongebob Squarepants')
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1 AND user_account.fullname = :fullname_1
+"""
+

# Specifying the FROM Clause and JOINs

As mentioned before, the FROM clause is automatically set based on the columns included as arguments in the select() method, without the need for explicit specification.

#     Even without specifying the FROM clause explicitly, it is set and displayed in the output.
+>>> print(select(user_table.c.name))
+"""
+SELECT user_account.name
+FROM user_account
+"""
+

If you want to reference columns from two different tables in the positional arguments of select(), you can separate them with a comma (,).

>>> print(select(user_table.c.name, address_table.c.email_address))
+"""
+SELECT user_account.name, address.email_address
+FROM user_account, address
+"""
+

If you want to join two different tables, there are two methods you can use:

One is the Select.join() method, which allows you to explicitly specify the left and right tables for the JOIN.

>>> print(
+...     select(user_table.c.name, address_table.c.email_address).
+...     join_from(user_table, address_table)
+... )
+"""
+SELECT user_account.name, address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

The other is to explicitly specify only the right table in the Select.join() method, and let the other table be implicitly referenced when selecting columns.

# This expression is the same, but the left table to join (user_table) is expressed implicitly.
+>>> print(
+...     select(user_table.c.name, address_table.c.email_address).
+...     join(address_table)
+... )
+"""
+SELECT user_account.name, address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

Alternatively, if you want to write the two JOINing tables more explicitly, or if you want to provide explicit additional options in the FROM clause, you can write it as follows.

>>> print(
+...     select(address_table.c.email_address).
+...     select_from(user_table).join(address_table)
+... )
+"""
+SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

Another case for using Select.select_from() is when we cannot implicitly set the FROM clause through the columns we want to query.

For example, to query count(*) in a typical SQL query, you would need to use sqlalchemy.sql.expression.func from SQLAlchemy.

>>> from sqlalchemy import func
+>>> print(select(func.count('*')).select_from(user_table))
+"""
+SELECT count(:count_2) AS count_1
+FROM user_account
+"""
+

# Setting the ON Clause

But there was something unusual, wasn't there? +In fact, in the previous example, when joining two tables using Select.select_from() or select.join(), the ON clause was implicitly set.

This automatic setting of the ON clause happened because the user_table and address_table objects have a ForeignKeyConstraint, i.e., a foreign key constraint, which led to the automatic setting.

If the two tables targeted for a Join lack such constraint keys, you must explicitly specify the ON clause. This functionality can be explicitly set by passing parameters to the Select.join() or Select.join_from() methods for the ON clause.

>>> print(
+...     select(address_table.c.email_address).
+...     select_from(user_table).
+...     join(address_table, user_table.c.id == address_table.c.user_id)
+... )
+"""
+SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

# OUTER, FULL Join

To implement LEFT OUTER JOIN or FULL OUTER JOIN In SQLAlchemy, you can use the keyword arguments Select.join.isouter and Select.join.full in the Select.join() and Select.join_from() methods.

An examples of implementing the LEFT OUTER JOIN:

>>> print(
+...     select(user_table).join(address_table, isouter=True)
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account LEFT OUTER JOIN address ON user_account.id = address.user_id
+"""
+

An examples of implementing the FULL OUTER JOIN:

>>> print(
+...     select(user_table).join(address_table, full=True)
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account FULL OUTER JOIN address ON user_account.id = address.user_id
+"""
+

# ORDER BY, GROUP BY, HAVING

  • The ORDER BY clause allows you to set the order of the rows retrieved by the SELECT clause.
  • The GROUP BY clause creates groups based on a specific column for rows aggregated by group functions.
  • HAVING applies conditions to groups created by the GROUP BY clause.

# ORDER BY

You can implement the ORDER BY feature using Select.order_by(). This method accepts Column objects or similar objects as positional arguments.

>>> print(select(user_table).order_by(user_table.c.name))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.name
+"""
+

Ascending and descending order can be implemented using the ColumnElement.asc() and ColumnElement.desc() modifiers, respectively.

The following example orders by the user_account.fullname column in descending order.

>>> print(select(User).order_by(User.fullname.desc()))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.fullname DESC
+"""
+

# Aggregations: GROUP BY, HAVING

In SQL, aggregate functions can also be used to combine multiple rows into a single row. Examples of aggregate functions include COUNT(), SUM(), and AVG().

SQLAlchemy provides SQL functions using the func namespace, where func creates a Function instance when given the name of an SQL function.

In the example below, the count() function is called to render the user_account.id column with the SQL COUNT() function.

>>> from sqlalchemy import func
+>>> count_fn = func.count(user_table.c.id)
+>>> print(count_fn)
+"""
+count(user_account.id)
+"""
+

More details about SQL functions are explained in Handling SQL Functions.

To summarize:

GROUP BY is a function needed to divide the retrieved rows into specific groups. In SQL, if a few columns are queried in the SELECT clause, these columns are directly or indirectly dependent on the primary key in the GROUP BY.

HAVING is necessary to apply conditions to groups created by GROUP BY (similar to the WHERE clause because it places conditions on groups).

In SQLAlchemy, GROUP BY and HAVING can be implemented using Select.group_by() and Select.having().

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         select(User.name, func.count(Address.id).label("count")).
+...         join(Address).
+...         group_by(User.name).
+...         having(func.count(Address.id) > 1)
+...     )
+...     print(result.all())
+""" The syntax above represents the SQL statement below.
+SELECT user_account.name, count(address.id) AS count
+FROM user_account JOIN address ON user_account.id = address.user_id GROUP BY user_account.name
+HAVING count(address.id) > ?
+[...] (1,)
+"""
+
+[('sandy', 2)]
+

# Grouping or ordering by alias

In some database backends, when using aggregate functions to query tables, it is important not to restate already specified aggregate functions in the ORDER BY or GROUP BY clauses.

# NOT GOOD
+SELECT id, COUNT(id) FROM user_account GROUP BY id ORDER BY count(id)
+
+# CORRECT
+SELECT id, COUNT(id) as cnt_id FROM user_account GROUP BY id ORDER BY cnt_id
+

Therefore, to implement ORDER BY or GROUP BY using aliases, you just need to insert the alias you want to use as an argument in the Select.order_by() or Select.group_by() methods.

The alias used here is not rendered first; instead, the alias used in the column clause is rendered first. If the rendered alias does not match anything in the rest of the query, an error occurs.

>>> from sqlalchemy import func, desc
+>>> # The alias 'num_addresses' is used in both the column and in the order_by clause.
+>>> stmt = select(
+...         Address.user_id,
+...         func.count(Address.id).label('num_addresses')).\
+...         group_by("user_id").order_by("user_id", desc("num_addresses"))
+>>> print(stmt)
+"""
+SELECT address.user_id, count(address.id) AS num_addresses
+FROM address GROUP BY address.user_id ORDER BY address.user_id, num_addresses DESC
+"""
+

# Using aliases

When using JOIN to query multiple tables, it's often necessary to repeatedly write the table names in the query.

In SQL, this issue can be addressed by giving aliases to table names or subqueries, reducing repetition.

In SQLAlchemy, such aliases can be implemented using the Core's FromClause.alias() function.

Within the Table object namespace, there are Column objects, allowing access to column names via Table.c.

print(select(user_table.c.name, user_table.c.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

Similarly, in the Alias object namespace, there are Column objects, making it possible to access columns via Alias.c.

>>> # Both user_alias_1 and user_alias_2 are Alias objects.
+>>> user_alias_1 = user_table.alias(‘table1’) 
+>>> user_alias_2 = user_table.alias(‘table2’)
+>>> # To access columns using the newly created table aliases,
+>>> # you should use Alias.c.column_name
+>>> print(
+...     select(user_alias_1.c.name, user_alias_2.c.name).
+...     join_from(user_alias_1, user_alias_2, user_alias_1.c.id > user_alias_2.c.id)
+... )
+
+"""
+SELECT table1.name, table2.name AS name_1 
+FROM user_account AS table1 JOIN user_account AS table2 ON table1.id > table2.id
+"""
+

# ORM Entity Aliases

The ORM in SQLAlchemy also has a function similar to the FromClause.alias() method, known as aliased()

This ORM aliased() function internally creates an Alias object for the originally mapped Table object, while maintaining ORM functionalities.

Tips:

The user_table and User were created in the previous chapter (opens new window), +where user_table is a Table object, and +User is an entity that inherits from the Base object and includes a Table object."

>>> user_alias_1 = user_table.alias()
+>>> user_alias_2 = user_table.alias()
+>>> # In the examples, it is applied to the User or Address entities.
+>>> print(
+...     select(User).
+...     join_from(User, address_alias_1).
+...     where(address_alias_1.email_address == 'patrick@aol.com').
+...     join_from(User, address_alias_2).
+...     where(address_alias_2.email_address == 'patrick@gmail.com')
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname 
+FROM user_account JOIN address AS address_1 ON user_account.id = address_1.user_id JOIN address AS address_2 ON user
+"""
+

# Subqueries and CTE(Common Table Expression)s

This section explains subqueries typically found in the FROM clause of a SELECT statement. It also covers CTEs (Common Table Expressions), which are used in a similar way to subqueries but with additional functionalities.

More about CTE

A CTE is a temporary result set within a query that can be referenced multiple times within the same query. +You can check the official links to describe CTEs in RDBMS below.

SQLAlchemy represents subqueries using the Subquery object created by Select.subquery(), and CTEs are represented using Select.cte().

>>> subq = select(
+...     func.count(address_table.c.id).label("count"),
+...     address_table.c.user_id
+... ).group_by(address_table.c.user_id).subquery()
+>>> print(subq)
+"""
+SELECT count(address.id) AS count, address.user_id
+FROM address GROUP BY address.user_id
+"""
+
+>>> # The ON clause automatically binds two tables
+>>> # that are already constrained by a foreign key.
+>>> stmt = select(
+...    user_table.c.name,
+...    user_table.c.fullname,
+...    subq.c.count
+... ).join_from(user_table, subq)
+>>> print(stmt)
+"""
+SELECT user_account.name, user_account.fullname, anon_1.count
+FROM user_account JOIN (SELECT count(address.id) AS count, address.user_id AS user_id
+FROM address GROUP BY address.user_id) AS anon_1 ON user_account.id = anon_1.user_id
+"""
+

# Hierarchy Query

The method of using CTE syntax in SQLAlchemy is almost identical to how subquery syntax is used. Instead of calling the Select.subquery() method, you use Select.cte(), allowing the resulting object to be used as a FROM element.

>>> subq = select(
+...     func.count(address_table.c.id).label("count"),
+...     address_table.c.user_id
+... ).group_by(address_table.c.user_id).cte()
+
+>>> stmt = select(
+...    user_table.c.name,
+...    user_table.c.fullname,
+...    subq.c.count
+... ).join_from(user_table, subq)
+
+>>> print(stmt)
+"""
+WITH anon_1 AS
+(SELECT count(address.id) AS count, address.user_id AS user_id
+FROM address GROUP BY address.user_id)
+ SELECT user_account.name, user_account.fullname, anon_1.count
+FROM user_account JOIN anon_1 ON user_account.id = anon_1.user_id
+"""
+

# ORM Entity Subqueries, CTE

You can see that aliased() performs the same operation for Subquery and CTE subqueries.

>>> subq = select(Address).where(~Address.email_address.like('%@aol.com')).subquery()
+>>> address_subq = aliased(Address, subq)
+>>> stmt = select(User, address_subq).join_from(User, address_subq).order_by(User.id, address_subq.id)
+>>> with Session(engine) as session:
+...     for user, address in session.execute(stmt):
+...         print(f"{user} {address}")
+
+""" The above syntax represents the following query:
+
+SELECT user_account.id, user_account.name, user_account.fullname,
+anon_1.id AS id_1, anon_1.email_address, anon_1.user_id
+FROM user_account JOIN
+(SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id
+FROM address
+WHERE address.email_address NOT LIKE ?) AS anon_1 ON user_account.id = anon_1.user_id
+ORDER BY user_account.id, anon_1.id
+[...] ('%@aol.com',)
+"""
+
+User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
+

Below is an example of querying the same result using the CTE constructor:

>>> cte = select(Address).where(~Address.email_address.like('%@aol.com')).cte()
+>>> address_cte = aliased(Address, cte)
+>>> stmt = select(User, address_cte).join_from(User, address_cte).order_by(User.id, address_cte.id)
+>>> with Session(engine) as session:
+...     for user, address in session.execute(stmt):
+...         print(f"{user} {address}")
+
+User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
+

# Scalar Subqueries and Correlated Queries

Before explaining scalar subqueries, let's briefly discuss subqueries in SQL. 출처:바이헨 블로그 (opens new window)

A "subquery" is a SELECT statement within another SQL statement, and the outer SQL statement is referred to as the "main query".

The types of subqueries are determined based on whether they reference columns of the main query, where they are declared, and the number of rows they return.

  • Classification based on reference to main query columns: +
    • Correlated Subqueries: The subquery references columns of the main query.
    • Non-correlated Subqueries: The subquery does not reference the main query's columns and operates independently, used to convey information to the main query.
  • Classification based on declaration position: +
    • Scalar Subqueries: Subqueries that appear in the column position of a SELECT statement (correlated).
    • Inline Views: Subqueries in the FROM clause (correlated).
    • Nested Subqueries: Subqueries in the WHERE clause (non-correlated).
  • Classification based on the number of rows returned: +
    • Single-row Subqueries (return one row)
    • Multi-row Subqueries (return more than one row): Used with IN, ANY, ALL, EXISTS.

In SQLAlchemy, scalar subqueries use ScalarSelect, which is part of the ColumnElement object, while general subqueries use Subquery, which is in the FromClause object.

Scalar subqueries are often used as described earlier in Aggregations.

# Implementing Scalar subquery using Select.scalar_subquery()
+>>> subq = select(func.count(address_table.c.id)).
+...             where(user_table.c.id == address_table.c.user_id).
+...             scalar_subquery()
+>>> print(subq) # ... is equal to "ScalarSelect" type
+"""
+(SELECT count(address.id) AS count_1
+FROM address, user_account
+WHERE user_account.id = address.user_id)
+"""
+

Scalar subqueries implemented using Select.scalar_subquery() render the user_account and address in the FROM clause, but since the user_account table is already present in the main query, it is not rendered again in the scalar subquery.

>>> stmt = select(user_table.c.name, subq.label("address_count"))
+>>> print(stmt)
+"""
+SELECT user_account.name, (SELECT count(address.id) AS count_1
+FROM address
+WHERE user_account.id = address.user_id) AS address_count
+FROM user_account
+"""
+

Meanwhile, when writing correlated queries, the connections between tables can become ambiguous.

I did not understand the correlated query example in the tutorial. +If someone understands it well, please contribute to this document.


# UNION, UNION ALL operators

In SQL, terms like UNION and UNION ALL are used to combine two SELECT statements. +Queries can be executed as shown below.

SELECT id FROM user_account
+union 
+SELECT email_address FROM address
+

Additionally, SQL supports set operations like INTERSECT (intersection) and EXCEPT (difference). +In SQLAlchemy, for Select objects, functions such as union(), intersect(), except_(), union_all(), intersect_all(), and except_all() are available.

The return value of these functions is a CompoundSelect, which is an object that can be used similarly to Select but has fewer methods. +The CompoundSelect object returned by union_all() can be executed with Connection.execute().

>>> from sqlalchemy import union_all
+>>> stmt1 = select(user_table).where(user_table.c.name == 'sandy')
+>>> stmt2 = select(user_table).where(user_table.c.name == 'spongebob')
+>>> u = union_all(stmt1, stmt2) # A value u is a CompoundSelect type.
+>>> with engine.connect() as conn:
+...     result = conn.execute(u)
+...     print(result.all())
+
+[(2, 'sandy', 'Sandy Cheeks'), (1, 'spongebob', 'Spongebob Squarepants')]
+

Just as Select provides the SelectBase.subquery() method to create Subquery objects, CompoundSelect objects can similarly be used as subqueries.

>>> u_subq = u.subquery()
+>>> stmt = (
+...     select(u_subq.c.name, address_table.c.email_address).
+...     join_from(address_table, u_subq).
+...     order_by(u_subq.c.name, address_table.c.email_address)
+... )
+>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[('sandy', 'sandy@sqlalchemy.org'), ('sandy','sandy@squirrelpower.org'), 
+('spongebob', 'spongebob@sqlalchemy.org')]
+

# EXISTS Subqueries

SQLAlchemy creates an Exists object through the SelectBase.exists() method to implement the EXISTS clause.

>>> # subq is a Exists type
+>>> subq = (
+...     select(func.count(address_table.c.id)).
+...     where(user_table.c.id == address_table.c.user_id).
+...     group_by(address_table.c.user_id).
+...     having(func.count(address_table.c.id) > 1)
+... ).exists()
+>>> print(subq)
+"""
+EXISTS (SELECT count(address.id) AS count_1 
+FROM address, user_account 
+WHERE user_account.id = address.user_id GROUP BY address.user_id 
+HAVING count(address.id) > :count_2)
+"""
+>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         select(user_table.c.name).where(subq)
+...     )
+...     print(result.all())
+
+[('sandy',)]
+

The EXISTS clause is more often used in a non-negated form by the way.

# This is a query to select usernames that do not have an email address.
+# Take a look at the part where the '~' operator is used."
+>>> subq = (
+...     select(address_table.c.id).
+...     where(user_table.c.id == address_table.c.user_id)
+... ).exists()
+>>> stmt = select(user_table.c.name).where(~subq)
+>>> print(stmt)
+"""
+SELECT user_account.id 
+FROM user_account 
+WHERE NOT (EXISTS (SELECT count(address.id) AS count_1 
+FROM address 
+WHERE user_account.id = address.user_id GROUP BY address.user_id 
+HAVING count(address.id) > :count_2))
+"""
+>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[('patrick',)]
+

# Dealing with SQL functions.

In the earlier section Aggregations: GROUP BY, HAVING, the func object, which acts as a factory for creating new Function objects, was introduced. When using syntax like select(), you can pass SQL functions created by the func object as arguments.

  • count() : Aggregate functions are used to print the number of rows.
    >>> # cnt is a type of  <class 'sqlalchemy.sql.functions.count'>.
    +>>> cnt = func.count() 
    +>>> print(select(cnt).select_from(user_table))
    +"""
    +SELECT count(*) AS count_1FROM user_account
    +"""
    +
  • lower() : String functions are used to convert strings to lowercase.
    >>> print(select(func.lower("A String With Much UPPERCASE")))
    +"""
    +SELECT lower(:lower_2) AS lower_1
    +"""
    +
  • now() : There is also a function that returns the current time and date. This function is commonly used, so SQLAlchemy helps in easily rendering it across different backends.
    >>> stmt = select(func.now())
    +>>> with engine.connect() as conn:
    +...     result = conn.execute(stmt)
    +...     print(result.all())
    +
    +[(datetime.datetime(...),)]
    +

Different database backends have SQL functions with different names. Therefore, func allows access to any name in its namespace, automatically interpreting that name as an SQL function and rendering it.

>>> # A data type of crazy_function is Function.
+>>> crazy_function = func.some_crazy_function(user_table.c.fullname, 17)
+>>> print(select(crazy_function))
+"""
+SELECT some_crazy_function(user_account.name, :some_crazy_function_2) AS some_crazy_function_1
+FROM user_account
+"""
+

Meanwhile, SQLAlchemy provides appropriate data types for commonly used SQL functions like count, now, max, concat, etc., specific to each backend.

>>> from sqlalchemy.dialects import postgresql
+>>> print(select(func.now()).compile(dialect=postgresql.dialect()))
+"""
+SELECT now() AS now_1
+"""
+
+>>> from sqlalchemy.dialects import oracle
+>>> print(select(func.now()).compile(dialect=oracle.dialect()))
+"""
+SELECT CURRENT_TIMESTAMP AS now_1 FROM DUAL
+"""
+

# Functions Have Return Types

I did not understand the part about 'Functions Have Return Types' in the original text. +If anyone understands this, please contribute to this section. Thank you.


# Built-in Functions Have Pre-Configured Return Types

I did not understand the part about 'Built-in Functions Have Pre-Configured Return Types' in the original text. +If anyone understands this, please contribute to this section. Thank you.


# WINDOW Functions

Window functions are similar to GROUP BY, created to easily define relationships between rows.

In SQLAlchemy, among all SQL functions created by the func namespace, there is the FunctionElement.over() method, which implements the OVER clause.

One of the window functions is row_number(), which counts the number of rows. You can group each row by username and then number the email addresses within each group.

# The FunctionElement.over.partition_by parameter is used
+# to render the PARTITION BY clause in the OVER clause.
+>>> stmt = select(
+...     func.row_number().over(partition_by=user_table.c.name),
+...     user_table.c.name,
+...     address_table.c.email_address
+... ).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+[(1, 'sandy', 'sandy@sqlalchemy.org'), 
+ (2, 'sandy', 'sandy@squirrelpower.org'), 
+ (1, 'spongebob', 'spongebob@sqlalchemy.org')]
+

FunctionElement.over.order_by can be used to apply an ORDER BY clause.

>>> stmt = select(
+...     func.count().over(order_by=user_table.c.name),
+...     user_table.c.name,
+...     address_table.c.email_address).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[(2, 'sandy', 'sandy@sqlalchemy.org'), 
+ (2, 'sandy', 'sandy@squirrelpower.org'), 
+ (3, 'spongebob', 'spongebob@sqlalchemy.org')]
+

# Special Modifiers like WITHIN GROUP, FILTER

The SQL clause WITHIN GROUP is used with ordered sets or hypothetical sets along with aggregate functions.

Common ordered set functions include percentile_cont() and rank().

In SQLAlchemy, functions such as rank, dense_rank, percentile_count, and percentile_disc are implemented, each with the FunctionElement.within_group() method.

>>> print(
+...     func.unnest(
+...         func.percentile_disc([0.25,0.5,0.75,1]).within_group(user_table.c.name)
+...     )
+... )
+"""
+unnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))
+"""
+

Some backends support the "FILTER" modifier, which can be utilized through the FunctionElement.filter() method in SQLAlchemy.

>>> stmt = select(
+...     func.count(address_table.c.email_address).filter(user_table.c.name == 'sandy'),
+...     func.count(address_table.c.email_address).filter(user_table.c.name == 'spongebob')
+... ).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+"""
+SELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,
+count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+
+('sandy', 'spongebob')
+[(2, 1)]
+

# Table-Valued Functions

I did not understand the part about 'Table-Valued Functions' in the original text. +If anyone understands this, please contribute to this section. Thank you.


# Column Value Functions or Scalar Column (Table Valued Functions)

One of the special syntaxes supported by Oracle and PostgreSQL is functions set in the FROM clause. Examples in PostgreSQL include json_array_elements(), json_object_keys(), json_each_text(), and json_each().

SQLAlchemy refers to these functions as column values and applies them using the FunctionElement.column_valued() specifier on a Function object.

>>> from sqlalchemy import select, func
+>>> stmt = select(func.json_array_elements('["one", "two"]').column_valued("x"))
+>>> print(stmt)
+"""
+SELECT x
+FROM json_array_elements(:json_array_elements_1) AS x
+"""
+

Column value functions can also be used in Oracle as custom SQL functions, as shown below.

>>> from sqlalchemy.dialects import oracle
+>>> stmt = select(func.scalar_strings(5).column_valued("s"))
+>>> print(stmt.compile(dialect=oracle.dialect()))
+"""
+SELECT COLUMN_VALUE s
+FROM TABLE (scalar_strings(:scalar_strings_1)) s
+"""
+
+ + + diff --git a/en/tutorial/5.2. Inserting Rows Using Core.html b/en/tutorial/5.2. Inserting Rows Using Core.html new file mode 100644 index 0000000..92020a2 --- /dev/null +++ b/en/tutorial/5.2. Inserting Rows Using Core.html @@ -0,0 +1,107 @@ + + + + + + Inserting Rows Using Core | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Inserting Rows Using Core

In this chapter, we learn how to INSERT data using the SQLAlchemy Core approach.


# Constructing SQL Expressions with insert()

First, you can create an INSERT statement like this:

>>> from sqlalchemy import insert
+
+#  stmt is an instance of the Insert object.
+>>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")
+>>> print(stmt)
+'INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)'
+

Here, user_table is the Table object we created in the previous chapter. We created it as follows.

from sqlalchemy import MetaData
+from sqlalchemy import Table, Column, Integer, String
+
+metadata = MetaData()
+user_table = Table(
+    'user_account',
+    metadata,
+    Column('id', Integer, primary_key=True),
+    Column('name', String(30)),
+    Column('fullname', String),
+)
+

Looking at stmt, you'll notice that the parameters have not yet been mapped. +This can be checked after compile() it, as shown next.

>>> compiled = stmt.compile()
+>>> print(compiled.params)
+{'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}
+

# Executing the Statement

Now, let's execute the INSERT statement we created above using the Core approach.

>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     conn.commit()
+
+# The above code executes the following query.
+
+BEGIN (implicit)
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('spongebob', 'Spongebob Squarepants')
+COMMIT
+

What information does the result contain, which is obtained from the return value of conn.execute(stmt)? +result is a CursorResult (opens new window) object. +It holds various information about the execution results, particularly the Row (opens new window) objects that contain data rows.

Since we have just inserted data, we can check the primary key value of the inserted data as follows.

>>> result.inserted_primary_key  # This is also a Row object.
+(1, )  # As the primary key can be composed of multiple columns, it is represented as a tuple.
+

# Passing INSERT Parameters to Connection.execute()

Above, we created a statement that included values along with insert.

>>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")
+

However, besides this method, you can also execute an INSERT statement by passing parameters to the Connection.execute() method. The official documentation suggests this as a more common approach.

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         insert(user_table),
+...         [
+...             {"name": "sandy", "fullname": "Sandy Cheeks"},
+...             {"name": "patrick", "fullname": "Patrick Star"}
+...         ]
+...     )
+...     conn.commit()
+

The official documentation also explains how to execute statements including subqueries in a separate section. However, it has been deemed not entirely suitable for the tutorial content and is not included in this text. +For those interested in this topic, please refer to the original documentation (opens new window).


# Insert.from_select()

Sometimes you need a query to INSERT rows that are received from a SELECT statement, as in the following example.

Such cases can be written as shown in the following code.

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
+>>> insert_stmt = insert(address_table).from_select(
+...     ["user_id", "email_address"], select_stmt
+... )
+>>> print(insert_stmt)
+"""
+INSERT INTO address (user_id, email_address)
+SELECT user_account.id, user_account.name || :name_1 AS anon_1
+FROM user_account
+"""
+

# Insert.returning()

There are situations where you need to receive the value of the processed rows from the database after query processing. This is known as the RETURNING syntax. +For an introduction to this, it would be good to read this wiki (opens new window).

In SQLAlchemy Core, this RETURNING syntax can be written as follows.

>>> insert_stmt = insert(address_table).returning(address_table.c.id, address_table.c.email_address)
+>>> print(insert_stmt)
+"""
+INSERT INTO address (id, user_id, email_address)
+VALUES (:id, :user_id, :email_address)
+RETURNING address.id, address.email_address
+"""
+
+ + + diff --git a/en/tutorial/5.3. Modifying and Deleting Rows Using Core.html b/en/tutorial/5.3. Modifying and Deleting Rows Using Core.html new file mode 100644 index 0000000..369e228 --- /dev/null +++ b/en/tutorial/5.3. Modifying and Deleting Rows Using Core.html @@ -0,0 +1,150 @@ + + + + + + Modifying and Deleting Rows Using Core | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Modifying and Deleting Rows Using Core

In this chapter, we explain the Update and Delete statements used for modifying and deleting existing rows using the Core approach in SQLAlchemy.


# Constructing SQL Expressions with update()

You can write an UPDATE statement as follows.

>>> from sqlalchemy import update
+>>> stmt = (
+...     update(user_table).where(user_table.c.name == 'patrick').
+...     values(fullname='Patrick the Star')
+... )
+>>> print(stmt)
+'UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1'
+
>>> stmt = (
+...     update(user_table).
+...     values(fullname="Username: " + user_table.c.name)
+... )
+>>> print(stmt)
+'UPDATE user_account SET fullname=(:name_1 || user_account.name)'
+

The original text discusses bindparam(), but since I haven't seen many use cases for it, it is omitted in this text. If you're curious, please refer to the original content (opens new window).


# Correlated Update

Using a Correlated Subquery (opens new window), you can utilize rows from another table as follows.

>>> scalar_subq = (
+...   select(address_table.c.email_address).
+...   where(address_table.c.user_id == user_table.c.id).
+...   order_by(address_table.c.id).
+...   limit(1).
+...   scalar_subquery()
+... )
+>>> update_stmt = update(user_table).values(fullname=scalar_subq)
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=(SELECT address.email_address
+FROM address
+WHERE address.user_id = user_account.id ORDER BY address.id
+LIMIT :param_1)
+"""
+

When updating a table, there are times when you need to set conditions in relation to information from another table. +In such cases, you can use it as shown in the example below.

>>> update_stmt = (
+...    update(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com').
+...    values(fullname='Pat')
+...  )
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=:fullname FROM address
+WHERE user_account.id = address.user_id AND address.email_address = :email_address_1
+"""
+

# Updating Multiple Tables Simultaneously

You can simultaneously update specific values in multiple tables that meet certain conditions, as shown in the following example.

>>> update_stmt = (
+...    update(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com').
+...    values(
+...        {
+...            user_table.c.fullname: "Pat",
+...            address_table.c.email_address: "pat@aol.com"
+...        }
+...    )
+...  )
+>>> from sqlalchemy.dialects import mysql
+>>> print(update_stmt.compile(dialect=mysql.dialect()))
+"""
+UPDATE user_account, address
+SET address.email_address=%s, user_account.fullname=%s
+WHERE user_account.id = address.user_id AND address.email_address = %s
+"""
+

I did not include a summary of the 'Parameter Ordered Updates (opens new window)' section from the original text because I did not understand it. +If someone understands this part well, it would be appreciated if you could contribute to this document.


# Constructing SQL Expressions with delete()

You can write a DELETE statement as follows.

>>> from sqlalchemy import delete
+>>> stmt = delete(user_table).where(user_table.c.name == 'patrick')
+>>> print(stmt)
+"""
+DELETE FROM user_account WHERE user_account.name = :name_1
+"""
+

# Deleting with a JOIN to Another Table

There are cases where you need to delete data that meets specific conditions after joining with another table. (If this is unclear, refer to this article (opens new window) for clarification.) +In such cases, you can use it as shown in the example below.

>>> delete_stmt = (
+...    delete(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com')
+...  )
+>>> from sqlalchemy.dialects import mysql
+>>> print(delete_stmt.compile(dialect=mysql.dialect()))
+"""
+DELETE FROM user_account USING user_account, address
+WHERE user_account.id = address.user_id AND address.email_address = %s
+"""
+

# Getting the Number of Rows Affected in UPDATE, DELETE

You can obtain the number of rows processed by a query using the 'Result.rowcount' (opens new window) property, as shown next.

>>> with engine.begin() as conn:
+...     result = conn.execute(
+...         update(user_table).
+...         values(fullname="Patrick McStar").
+...         where(user_table.c.name == 'patrick')
+...     )
+...     print(result.rowcount)  # You can use the rowcount property of the Result object.
+
+1  # The number of rows processed by the query (the same as the number of rows matching the conditions).
+

# Using RETURNING with UPDATE, DELETE

You can use the RETURNING syntax as follows.

For more on the RETURNING syntax, please see this article (opens new window).

>>> update_stmt = (
+...     update(user_table).where(user_table.c.name == 'patrick').
+...     values(fullname='Patrick the Star').
+...     returning(user_table.c.id, user_table.c.name)
+... )
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=:fullname
+WHERE user_account.name = :name_1
+RETURNING user_account.id, user_account.name
+"""
+
>>> delete_stmt = (
+...     delete(user_table).where(user_table.c.name == 'patrick').
+...     returning(user_table.c.id, user_table.c.name)
+... )
+>>> print(delete_stmt)
+"""
+DELETE FROM user_account
+WHERE user_account.name = :name_1
+RETURNING user_account.id, user_account.name
+"""
+
+ + + diff --git a/en/tutorial/6. Manipulating Data Using ORM.html b/en/tutorial/6. Manipulating Data Using ORM.html new file mode 100644 index 0000000..ba65f45 --- /dev/null +++ b/en/tutorial/6. Manipulating Data Using ORM.html @@ -0,0 +1,206 @@ + + + + + + Manipulating Data Using ORM | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Manipulating Data Using ORM

Until the previous chapter, we focused on utilizing queries from the CORE perspective.

In this chapter, we explain the components, lifecycle, and interaction methods of the Session used in the ORM approach.


# Inserting rows with ORM

The Session object, when using ORM, creates Insert objects and emits them in transactions. Session adds object entries to perform these processes. Then, through a process called flush, it records the new items in the database.

# Instances of Objects Representing Rows

In the previous process, we executed INSERT using a Python Dictionary.

In ORM, we directly use user-defined Python objects defined in the table metadata definition.

>>> squidward = User(name="squidward", fullname="Squidward Tentacles")
+>>> krabs = User(name="ehkrabs", fullname="Eugene H. Krabs")
+

We create two User objects that represent potential database rows to be INSERTed. Because of __init__() constructor automatically created by ORM mapping, we can create each object using the constructor's column names as keys.

>>> squidward
+User(id=None, name='squidward', fullname='Squidward Tentacles')
+

Similar to Core's Insert, ORM integrates it even without including a primary key. The None value for id is provided by SQLAlchemy to indicate that the attribute does not have a value yet.

Currently, the two objects (squiward and krabs) are in a state called transient. The transient state means they are not yet connected to any database and not yet associated with a Session object that can generate an INSERT statement.

# Adding Objects to the Session

>>> session = Session(engine)   # It is essential to close after use.
+>>> session.add(squidward)      # Insert an object into session via Session.add() method.
+>>> session.add(krabs)
+

When an object is added to the Session through Session.add(), it is called being in the pending state. +The pending state means the object has not yet been added to the database.

>>> session.new   # You can check the objects in the pending state through session.new. Objects are added to the Session using the Session.add() method.
+IdentitySet([User(id=None, name='squidward', fullname='Squidward Tentacles'), User(id=None, name='ehkrabs', fullname='Eugene H. Krabs')])
+
  • IdentitySet is a Python set that hashes object IDs in all cases.
  • That is, it uses the id() method, not the hash() function of Python's built-in functions."

# Flushing

The Session object uses the unit of work pattern (opens new window). This means that it accumulates changes but does not actually communicate with the database until necessary. +This behavior allows objects in the previously mentioned pending state to be used more efficiently in SQL DML. +The process of actually sending the current changes to the Database via SQL is called flushing.

>>> session.flush()
+"""
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('squidward', 'Squidward Tentacles')
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('ehkrabs', 'Eugene H. Krabs')
+"""
+

Now, the transaction remains open until one of Session.commit(), Session.rollback(), or Session.close() is invoked.

While you can use Session.flush() directly to push the current pending contents, Session typically features autoflush, so this is usually not necessary. Session.commit() flushes changes every time it is called.

# Automatically Generated Primary Key Properties

When a row is inserted, the Python object we created becomes persistent. +The persistent state is associated with the loaded Session object.

During INSERT, the ORM retrieves the primary key identifier for each new object. +This uses the same CursorResult.inserted_primary_key accessor introduced earlier.

>>> squidward.id
+4
+>>> krabs.id
+5
+

When ORM is flushed, instead of executemany, two separate INSERT statements are used because of this CursorResult.inserted_primary_key. +In SQLite, for instance, you need to INSERT one column at a time to use the auto-increment feature (other various databases like PostgreSQL's IDENTITY or SERIAL function similarly). +If a database connection like psycopg2, which can provide primary key information for many rows at once, is used, the ORM optimizes this to INSERT many rows at once."

# Identity Map

Identity Map (ID Map) is an in-memory storage that links all objects currently loaded in memory to their primary key IDs. You can retrieve one of these objects through Session.get(). This method searches for the object in the ID Map if it's in memory, or through a SELECT statement if it's not.

>>> some_squidward = session.get(User, 4)
+>>> some_squidward
+User(id=4, name='squidward', fullname='Squidward Tentacles')
+

An important point is that the ID Map maintains unique objects among Python objects.

>>> some_squidward is squidward 
+True
+

The ID Map is a crucial feature that allows manipulation of complex object sets within a transaction in an unsynchronized state.

# Committing

We now commit the current changes to the transaction.

>>> session.commit()
+COMMIT
+

# How to UPDATE ORM objects

There are two ways to perform an UPDATE through ORM:

  1. Using the unit of work pattern employed by Session. UPDATE operations for each primary key with changes are sent out in sequence.
  2. Known as "ORM usage update", where you can explicitly use the Update construct with Session."

# Updating changes automatically

>>> sandy = session.execute(select(User).filter_by(name="sandy")).scalar_one()
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('sandy',)
+"""
+

This 'Sandy' user object acts as a proxy for a row in the database, more specifically, for the row with primary key 2 from the transaction's perspective.

>>> sandy
+User(id=2, name='sandy', fullname='Sandy Cheeks')
+>>> sandy.fullname = "Sandy Squirrel"   # When an object's attribute is changed, the Session records this change.
+>>> sandy in session.dirty              # Such changed objects are referred to as 'dirty' and can be checked in session.dirty.
+True
+

When the Session executes flush, an UPDATE is executed in the database, actually updating the values in the database. If a SELECT statement is executed afterwards, a flush is automatically executed, allowing you to immediately retrieve the updated name value of Sandy through SELECT.

>>> sandy_fullname = session.execute(
+...     select(User.fullname).where(User.id == 2)
+... ).scalar_one()
+"""
+UPDATE user_account SET fullname=? WHERE user_account.id = ?
+[...] ('Sandy Squirrel', 2)
+SELECT user_account.fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (2,)
+"""
+>>> print(sandy_fullname)
+Sandy Squirrel
+# Using the flush, Sandy's changes are actually reflected in the database,
+# causing the object to lose its 'dirty' status.
+>>> sandy in session.dirty 
+False
+

# ORM usage update

The last method to perform an UPDATE through ORM is to explicitly use 'ORM usage update'. This allows you to use a general SQL UPDATE statement that can affect many rows at once.

>>> session.execute(
+...     update(User).
+...     where(User.name == "sandy").
+...     values(fullname="Sandy Squirrel Extraordinaire")
+... )
+"""
+UPDATE user_account SET fullname=? WHERE user_account.name = ?
+[...] ('Sandy Squirrel Extraordinaire', 'sandy')
+"""
+<sqlalchemy.engine.cursor.CursorResult object ...>
+

If there are objects in the current Session that match the given conditions, the corresponding update will also be reflected in these objects.

>>> sandy.fullname
+'Sandy Squirrel Extraordinaire'
+

# How to Delete ORM objects

You can mark individual ORM objects for deletion using the Session.delete() method. Once delete is executed, objects in that Session become expired.

>>> patrick = session.get(User, 3)
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (3,)
+"""
+>>> session.delete(patrick)     # Indicate that patrick will be deleted
+>>> session.execute(
+...     select(User)
+...     .where(User.name == "patrick")
+... ).first()                   # Execute flush at this point
+"""
+SELECT address.id AS address_id, address.email_address AS address_email_address,
+address.user_id AS address_user_id
+FROM address
+WHERE ? = address.user_id
+[...] (3,)
+DELETE FROM user_account WHERE user_account.id = ?
+[...] (3,)
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('patrick',)
+"""
+>>> squidward in session # Once expired in the Session, the object is removed from the session.
+False
+

Like the 'Sandy' used in the above UPDATE, these actions are only within the ongoing transaction and can be undone at any time unless committed.

# ORM usage delete

Like UPDATE, there is also 'ORM usage delete'.

# This is just an example, not a necessary operation for delete.
+>>> squidward = session.get(User, 4)
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (4,)
+"""
+
+>>> session.execute(delete(User).where(User.name == "squidward"))
+"""
+DELETE FROM user_account WHERE user_account.name = ?
+[...] ('squidward',)
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+"""
+

# Rolling Back

Session has a Session.rollback() method to roll back the current operations. This method affects Python objects like the aforementioned sandy. +Calling Session.rollback() not only rolls back the transaction but also turns all objects associated with this Session into expired status. This state change triggers a self-refresh the next time the object is accessed, a process known as lazy loading.

>>> session.rollback()
+ROLLBACK
+

Looking closely at sandy, which is in the expired state, you can see that no other information remains except for special SQLAlchemy-related status objects.

>>> sandy.__dict__
+{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>}
+>>> sandy.fullname      # Since the session is expired, accessing the object properties will trigger a new transaction.
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (2,)
+"""
+'Sandy Cheeks'
+>>> sandy.__dict__    # Now you can see that the database row is also filled in the sandy object.
+{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>,
+ 'id': 2, 'name': 'sandy', 'fullname': 'Sandy Cheeks'}
+

For the deleted objects, you can see that they are restored in the Session and appear again in the database.

>>> patrick in session
+True
+>>> session.execute(select(User).where(User.name == 'patrick')).scalar_one() is patrick
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('patrick',)
+"""
+True
+

# Closing the Session

We have handled the Session outside of the context structure, and in such cases, it is good practice to explicitly close the Session as follows:

>>> session.close()
+ROLLBACK
+

Similarly, when a Session created through a context statement is closed within the context statement, the following actions are performed.

  • Cancel all ongoing transactions (e.g., rollbacks) to release all connection resources to the connection pool. +
    • This means you don't need to explicitly call Session.rollback() to check if the transaction was rolled back when closing the Session after performing some read-only operations with it. The connection pool handles this.
  • Remove all objects from the Session. +
    • This means that all Python objects loaded for this Session, such as sandy, patrick, and squidward, are now in a detached state. For instance, an object that was in the expired state is no longer associated with a database transaction to refresh data due to a Session.commit() call, and it does not contain the current row's state.
    • >>> squidward.name
      +Traceback (most recent call last):
      +...
      +sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x...> is not bound to a Session; attribute refresh operation cannot proceed
      +
    • Detached objects can be reassociated with the same or a new Session using the Session.add() method, re-establishing the relationship with a specific database row.
    • >>> session.add(squidward)    # Reconnect to the session
      +>>> squidward.name            # Retrieve the information through the transaction again.
      +"""
      +SELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname
      +FROM user_account
      +WHERE user_account.id = ?
      +[...] (4,)
      +"""
      +'squidward'
      +

Objects in the detached state should ideally be avoided. When a Session is closed, it cleans up references to all previously connected objects. Typically, the need for detached objects arises in web applications when an object has just been committed and the Session is closed before it is rendered in a view. In this case, set the Session.expire_on_commit flag to False.

+ + + diff --git a/en/tutorial/7. Working with Related Objects Using ORM.html b/en/tutorial/7. Working with Related Objects Using ORM.html new file mode 100644 index 0000000..ea2220d --- /dev/null +++ b/en/tutorial/7. Working with Related Objects Using ORM.html @@ -0,0 +1,357 @@ + + + + + + Working with Related Objects Using ORM | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Working with Related Objects Using ORM


In this chapter, we will cover another essential ORM concept, which is the interaction with mapped objects that reference other objects.

relationship() defines the relationship between two mapped objects and is also known as self-referencing.

For simplicity, we will omit Column mappings and other directives, and explain relationship() in a shortened form.


from sqlalchemy.orm import relationship
+
+
+class User(Base):
+    __tablename__ = 'user_account'
+
+    # ... Column mappings
+
+    addresses = relationship("Address", back_populates="user")
+
+
+class Address(Base):
+    __tablename__ = 'address'
+
+    # ... Column mappings
+
+    user = relationship("User", back_populates="addresses")
+

In the structure shown, the User object has a variable addresses, and the Address object has a variable user.

Both are created as relationship objects, but these aren't actual database columns but are set up to allow easy access in the code.

In other words, it facilitates easy navigation from a User object to an Address object.

Additionally, the back_populates parameter in the relationship declaration allows for the reverse situation, i.e., navigating from an Address object to a User object.

In relational Database terms, it naturally sets a 1 : N relationship as an N : 1 relationship.

In the next section, we will see what role the relationship() object's instances play and how they function.



When a new User object is created, the .addresses collection appears as a List object.

>>> u1 = User(name='pkrabs', fullname='Pearl Krabs')    
+>>> u1.addresses
+[]
+

You can add an Address object using list.append().

>>> a1 = Address(email_address="pear1.krabs@gmail.com")
+>>> u1.addresses.append(a1)
+
+# The u1.addresses collection now includes the new Address object.
+>>> u1.addresses
+[Address(id=None, email_address='pearl.krabs@gmail.com')]
+

If an Address object is associated with the User.addresses collection, another action occurs in the variable u1. The User.addresses and Address.user relationship is synchronized, allowing you to move: +- From a User object to an Address, and +- Back from an Address object to a User.

>>> a1.user
+User(id=None, name='pkrabs', fullname='Pearl Krabs')
+

This is the result of synchronization using relationship.back_populates between the two relationship() objects.

The relationship() parameter can be complementarily assigned/list modified to another variable. Creating another Address object and assigning it to the Address.user property makes it part of the User.addresses collection.

>>> a2 = Address(email_address="pearl@aol.com", user=u1)
+>>> u1.addresses
+[Address(id=None, email_address='pearl.krabs@gmail.com'), Address(id=None, email_address='pearl@aol.com')]
+

We actually used the variable u1 as a keyword argument for user as if it were a property declared in the object (Address). It's equivalent to assigning the property afterward.

# equivalent effect as a2 = Address(user=u1)
+>>> a2.user = u1
+

# Cascading Objects in the Session


We now have two related User and Address objects in a bidirectional structure in memory, but as mentioned earlier in Inserting Rows with ORM , these objects are in a transient state in the Session until they are associated with it.

We need to see when using Session.add(), and applying the method to the User object, that the related Address objects are also added.

>>> session.add(u1)
+>>> u1 in session
+True
+>>> a1 in session
+True
+>>> a2 in session 
+True
+

The three objects are now in a pending state, which means no INSERT operations have been executed yet. The three objects have not been assigned primary keys, and the a1 and a2 objects have a column (user_id) reference property. This is because the objects are not yet actually connected to a real database.

>>> print(u1.id)
+None
+>>> print(a1.user_id)
+None
+

Let's save it to the database.

>>> session.commit()
+

If we translate the implemented code into SQL queries, it would look like this.

INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('pkrabs', 'Pearl Krabs')
+INSERT INTO address (email_address, user_id) VALUES (?, ?)
+[...] ('pearl.krabs@gmail.com', 6)
+INSERT INTO address (email_address, user_id) VALUES (?, ?)
+[...] ('pearl@aol.com', 6)
+COMMIT
+

Using session, you can automate SQL INSERT, UPDATE, DELETE statements.

Finally, executing Session.commit() ensures all steps are called in the correct order, and the primary key of address.user_id is applied in the user_account.


# Loading Relationships


After calling Session.commit(), you can see the primary key created for the u1 object.

>>> u1.id
+6
+

The above code is equivalent to executing the following query.

BEGIN (implicit)
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (6,)
+

You can also see that ids are now present in the objects linked to u1.addresses.

To retrieve these objects, we can observe the lazy load approach.

lazy loading : This is a method where a SELECT statement is executed to fetch information only when someone tries to access that information. In other words, it retrieves the necessary information as needed.

>>> u1.addresses
+[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]
+
SELECT address.id AS address_id, address.email_address AS address_email_address,
+address.user_id AS address_user_id
+FROM address
+WHERE ? = address.user_id
+[...] (6,)
+

SQLAlchemy ORM’s default for collections and related properties is lazy loading. This means once a collection has been relationshipped, as long as the data exists in memory, it remains accessible.

>>> u1.addresses
+[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]
+

Although lazy loading can be costly without explicit steps for optimization, it is optimized at least not to perform redundant operations.

You can also see the a1 and a2 objects in the u1.addresses collection.

>>> a1
+Address(id=4, email_address='pearl.krabs@gmail.com')
+>>> a2
+Address(id=5, email_address='pearl@aol.com')
+

We will provide a further introduction to the concept of relationship in the latter part of this section.


# Using relationship in Queries


This section introduces several ways in which relationship() helps automate SQL query construction.


# JOIN tables using relationship()

In Specifying the FROM and JOIN Clauses and WHERE Clauses sections, we used Select.join() and Select.join_from() methods to construct SQL JOINs. These methods infer the ON clause based on whether there's a ForeignKeyConstraint object linking the two tables or provide specific SQL Expression syntax representing the ON clause.

relationship() objects can be used to set the ON clause for joins. +A relationship() corresponding object can be passed as a single argument to Select.join(), serving as both the right join and the ON clause.

>>> print(
+...     select(Address.email_address).
+...     select_from(User).
+...     join(User.addresses)
+... )
+

The above code is equivalent to executing the following query.

SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+

If relationship() is not specified in Select.join() or Select.join_from(), no ON clause is used. This means it functions due to the ForeignKeyConstraint between the two mapped table objects, not because of the relationship() object of User and Address.

>>> print(
+...    select(Address.email_address).
+...    join_from(User, Address)
+... )
+

The above code is equivalent to executing the following query.

SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+

# Joining Using Aliases(aliased)

When configuring SQL JOINs using relationship(), it's suitable to use [PropComparator.of_type()] with aliased() cases. However, relationship() is used to configure the same joins as described in [ORM Entity Aliases].

You can directly use aliased() in a join with relationship().

>>> from sqlalchemy.orm import aliased
+>>> address_alias_1 = aliased(Address)
+>>> address_alias_2 = aliased(Address)
+>>> print(
+...     select(User).
+...     join_from(User, address_alias_1).
+...     where(address_alias_1.email_address == 'patrick@aol.com').
+...     join_from(User, address_alias_2).
+...     where(address_alias_2.email_address == 'patrick@gmail.com')
+... )
+

The above code is equivalent to executing the following query.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+JOIN address AS address_1 ON user_account.id = address_1.user_id
+JOIN address AS address_2 ON user_account.id = address_2.user_id
+WHERE address_1.email_address = :email_address_1
+AND address_2.email_address = :email_address_2
+

You can use join clause in aliased() object using relationship().

>>> user_alias_1 = aliased(User)
+>>> print(
+...     select(user_alias_1.name).
+...     join(user_alias_1.addresses)
+... )
+

The above code is equivalent to executing the following query.

SELECT user_account_1.name
+FROM user_account AS user_account_1
+JOIN address ON user_account_1.id = address.user_id
+

# Expanding ON Conditions

You can add conditions to the ON clause created by relation(). This feature is useful not only for quickly limiting the scope of a specific join for a related path but also for use cases like loader strategy configuration introduced in the last section. +PropComparator.and_() method allows a series of SQL expressions to be positionally combined in the JOIN's ON clause via AND. +For example, to limit the ON criteria to specific email addresses using User and Address, you would do this.

>>> stmt = (
+...   select(User.fullname).
+...   join(User.addresses.and_(Address.email_address == 'pearl.krabs@gmail.com'))
+... )
+
+>>> session.execute(stmt).all()
+[('Pearl Krabs',)]
+

The above code is equivalent to executing the following query.

SELECT user_account.fullname
+FROM user_account
+JOIN address ON user_account.id = address.user_id AND address.email_address = ?
+[...] ('pearl.krabs@gmail.com',)
+

# EXISTS has() , and()

In the EXISTS Subqueries section, the SQL EXISTS keyword was introduced along with the Scalar Subqueries, Correlated Queries section. +relationship() provides some help in commonly creating subqueries for relationships.


For a 1:N (one-to-many) relationship like User.addresses, you can use PropComparator.any() to create a subquery for the address table rejoining the user_account table. This method allows optional WHERE criteria to limit the rows matching the subquery.

>>> stmt = (
+...   select(User.fullname).
+...   where(User.addresses.any(Address.email_address == 'pearl.krabs@gmail.com'))
+... )
+
+>>> session.execute(stmt).all()
+[('Pearl Krabs',)]
+

The above code is equivalent to executing the following query.

SELECT user_account.fullname
+FROM user_account
+WHERE EXISTS (SELECT 1
+FROM address
+WHERE user_account.id = address.user_id AND address.email_address = ?)
+[...] ('pearl.krabs@gmail.com',)
+

Conversely, to find objects without related data, use ~User.addresses.any() to search for User objects.

>>> stmt = (
+...   select(User.fullname).
+...   where(~User.addresses.any())
+... )
+
+>>> session.execute(stmt).all()
+[('Patrick McStar',), ('Squidward Tentacles',), ('Eugene H. Krabs',)]
+

The above code is equivalent to executing the following query.

SELECT user_account.fullname
+FROM user_account
+WHERE NOT (EXISTS (SELECT 1
+FROM address
+WHERE user_account.id = address.user_id))
+[...] ()
+
+

PropComparator.has() works similarly to PropComparator.any() but is used for N:1 (Many-to-one) relationships. +For instance, to find all Address objects belonging to "pearl", you would use this method.

>>> stmt = (
+...   select(Address.email_address).
+...   where(Address.user.has(User.name=="pkrabs"))
+... )
+
+>>> session.execute(stmt).all()
+[('pearl.krabs@gmail.com',), ('pearl@aol.com',)]
+

The above code is equivalent to executing the following query.

SELECT address.email_address
+FROM address
+WHERE EXISTS (SELECT 1
+FROM user_account
+WHERE user_account.id = address.user_id AND user_account.name = ?)
+[...] ('pkrabs',)
+

# Relationship Operators

Several types of SQL creation helpers come with relationship():

  • N : 1 (Many-to-one) comparison +You can select rows where the foreign key of the target entity matches the primary key value of a specified object instance in an N:1 relationship.
>>> print(select(Address).where(Address.user == u1))
+

The above code is equivalent to executing the following query.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE :param_1 = address.user_id
+
  • NOT N : 1 (Many-to-one) comparison +You can use the not equal (!=) operator.
>>> print(select(Address).where(Address.user != u1))
+

The above code is equivalent to executing the following query.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE address.user_id != :user_id_1 OR address.user_id IS NULL
+
  • You can check if an object is included in a 1:N (one-to-many) collection.
>>> print(select(User).where(User.addresses.contains(a1)))
+

The above code is equivalent to executing the following query.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.id = :param_1
+
  • You can check if an object in a 1:N relationship is part of a specific parent item. with_parent() creates a comparison that returns rows referencing the given parent item, equivalent to using the == operator."
>>> from sqlalchemy.orm import with_parent
+>>> print(select(Address).where(with_parent(u1, User.addresses)))
+

The above code is equivalent to executing the following query.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE :param_1 = address.user_id
+

# Types of Relationship Loading


In the Loading Relationships section, we introduced the concept that when working with mapped object instances and accessing mapped attributes using relationship(), objects that should be in this collection are loaded, and if the collection is not filled, lazy load occurs.

Lazy loading is one of the most famous ORM patterns and also the most controversial. If dozens of ORM objects in memory each refer to a few unloaded properties, the routine manipulation of objects can implicitly release many problems (N+1 Problem), which can accumulate. Such implicit queries may not work at all when attempting database transformations that are no longer viable or when using alternative concurrency patterns like asynchronous.

What is a N + 1 Problem? +It's a problem where you fetch N records with one query, but to get the desired data, you end up performing a secondary query for each of these N records.

Lazy loading is a very popular and useful pattern when it is compatible with the concurrency approach in use and does not cause other problems. For this reason, SQLAlchemy's ORM focuses on features that allow you to permit and optimize these load behaviors.

Above all, the first step to effectively using ORM's lazy loading is to test the Application and check the SQL. +If inappropriate loads occur for objects detached from the Session, the use of Types of Relationship Loading should be reviewed.

You can mark objects to be associated with a SELECT statement using the Select.options() method.

for user_obj in session.execute(
+    select(User).options(selectinload(User.addresses))
+).scalars():
+    user_obj.addresses  # access addresses collection already loaded
+

You can also configure it as a default for relationship() using relationship.lazy.

from sqlalchemy.orm import relationship
+class User(Base):
+    __tablename__ = 'user_account'
+
+    addresses = relationship("Address", back_populates="user", lazy="selectin")
+

cf. Two Techniques of Relationship Loading


# Select IN loading Method

The most useful loading option in recent SQLAlchemy versions is selectinload(). This option solves the most common form of the "N+1 Problem" problem, which is an issue with sets of objects referencing related collections. It typically uses a SELECT form that can be sent out for the related table without introducing JOINs or subqueries and only queries for parent objects whose collections are not loaded.

The following example shows the Address objects related to a User object being loaded with selectinload(). During the Session.execute() call, two SELECT statements are generated in the database, with the second fetching the related Address objects.

>>> from sqlalchemy.orm import selectinload
+>>> stmt = (
+...   select(User).options(selectinload(User.addresses)).order_by(User.id)
+... )
+>>> for row in session.execute(stmt):
+...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
+spongebob  (spongebob@sqlalchemy.org)
+sandy  (sandy@sqlalchemy.org, sandy@squirrelpower.org)
+patrick  ()
+squidward  ()
+ehkrabs  ()
+pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)
+

The above code is equivalent to executing the following query.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.id
+[...] ()
+SELECT address.user_id AS address_user_id, address.id AS address_id,
+address.email_address AS address_email_address
+FROM address
+WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
+[...] (1, 2, 3, 4, 5, 6)
+

# Joined Loading Method

Joined Loading, the oldest in SQLAlchemy, is a type of eager loading, also known as joined eager loading. It is best suited for loading objects in "N:1 relationships", as it performs a SELECT JOIN of the tables specified in relationship(), fetching all table data at once.

For example, where an Address object has a connected user, an INNER JOIN can be used rather than an OUTER JOIN.

>>> from sqlalchemy.orm import joinedload
+>>> stmt = (
+...   select(Address).options(joinedload(Address.user, innerjoin=True)).order_by(Address.id)
+... )
+>>> for row in session.execute(stmt):
+...     print(f"{row.Address.email_address} {row.Address.user.name}")
+
+spongebob@sqlalchemy.org spongebob
+sandy@sqlalchemy.org sandy
+sandy@squirrelpower.org sandy
+pearl.krabs@gmail.com pkrabs
+pearl@aol.com pkrabs
+

The above code is equivalent to executing the following query.

SELECT address.id, address.email_address, address.user_id, user_account_1.id AS id_1,
+user_account_1.name, user_account_1.fullname
+FROM address
+JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
+ORDER BY address.id
+[...] ()
+

joinedload() is also used for 1: N collections but should be evaluated case-by-case compared to other options like selectinload() due to its nested collections and larger collections.

It's important to note that the WHERE and ORDER BY criteria of the SELECT query do not target the table rendered by joinload(). In the SQL query above, you can see an anonymous alias applied to the user_account table, which cannot directly address. This concept is further explained in the [Zen of joined Eager Loading] section.

The ON clause by joinedload() can be directly influenced using the method described previously in Expanding ON Conditions.

cf.

In general cases, "N+1 problem" is much less prevalent, so many-to-one eager loading is often unnecessary.

When many objects all reference the same related object (e.g., many Address objects referencing the same User), a single SQL for the User object is emitted using ordinary lazy loading.

The lazy loading routine queries the related object by the current primary key without emitting SQL if possible.


# Explicit Join + Eager Load Method

A common use case uses the contains_eager() option, which is very similar to joinedload() except it assumes you have set up the JOIN directly and instead marks additional columns in the COLUMNS clause that should be loaded into each object's related properties.

>>> from sqlalchemy.orm import contains_eager
+
+>>> stmt = (
+...   select(Address).
+...   join(Address.user).
+...   where(User.name == 'pkrabs').
+...   options(contains_eager(Address.user)).order_by(Address.id)
+... )
+
+>>> for row in session.execute(stmt):
+...     print(f"{row.Address.email_address} {row.Address.user.name}")
+
+pearl.krabs@gmail.com pkrabs
+pearl@aol.com pkrabs
+

The above code is equivalent to executing the following query.

SELECT user_account.id, user_account.name, user_account.fullname,
+address.id AS id_1, address.email_address, address.user_id
+FROM address JOIN user_account ON user_account.id = address.user_id
+WHERE user_account.name = ? ORDER BY address.id
+[...] ('pkrabs',)
+

For instance, we filtered user_account.name and loaded it into the returned Address.user property. A separate application of joinedload() would have unnecessarily created a twice-joined SQL query.

>>> stmt = (
+...   select(Address).
+...   join(Address.user).
+...   where(User.name == 'pkrabs').
+...   options(joinedload(Address.user)).order_by(Address.id)
+... )
+>>> print(stmt)  # SELECT has a JOIN and LEFT OUTER JOIN unnecessarily
+

The above code is equivalent to executing the following query.

SELECT address.id, address.email_address, address.user_id,
+user_account_1.id AS id_1, user_account_1.name, user_account_1.fullname
+FROM address JOIN user_account ON user_account.id = address.user_id
+LEFT OUTER JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
+WHERE user_account.name = :name_1 ORDER BY address.id
+

cf.

Two Techniques of Relationship Loading
Zen of joined Eager Loading


# Setting Loader Paths

The PropComparator.and_() method is actually generally usable for most loader options.

For example, if you want to reload usernames and email addresses from the sqlalchemy.org domain, you can limit the conditions with PropComparator.and_() applied to the arguments passed to selectinload().

>>> from sqlalchemy.orm import selectinload
+>>> stmt = (
+...   select(User).
+...   options(
+...       selectinload(
+...           User.addresses.and_(
+...             ~Address.email_address.endswith("sqlalchemy.org")
+...           )
+...       )
+...   ).
+...   order_by(User.id).
+...   execution_options(populate_existing=True)
+... )
+
+>>> for row in session.execute(stmt):
+...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
+
+spongebob  ()
+sandy  (sandy@squirrelpower.org)
+patrick  ()
+squidward  ()
+ehkrabs  ()
+pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)
+

The above code is equivalent to executing the following query.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.id
+[...] ()
+SELECT address.user_id AS address_user_id, address.id AS address_id,
+address.email_address AS address_email_address
+FROM address
+WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
+AND (address.email_address NOT LIKE '%' || ?)
+[...] (1, 2, 3, 4, 5, 6, 'sqlalchemy.org')
+

It's crucial to note the addition of the .execution_options(populate_existing=True) option above. When fetching rows, this option indicates that loader options must replace the existing collections' contents in already loaded objects.

Since we are iterating with a Session object, the objects being loaded here are the same Python instances as those initially maintained at the start of this tutorial's ORM section.


# Raise Loading Method

The raiseload() option is commonly used to completely block the occurrence of the "N+1 problem" by instead causing errors rather than slow loading.

There are two variants: blocking all "load" operations that include works that need SQL (lazy load) and those that only reference the current Session (raiseload.sql_only option).

class User(Base):
+    __tablename__ = 'user_account'
+
+    # ... Column mappings
+
+    addresses = relationship("Address", back_populates="user", lazy="raise_on_sql")
+
+
+class Address(Base):
+    __tablename__ = 'address'
+
+    # ... Column mappings
+
+    user = relationship("User", back_populates="addresses", lazy="raise_on_sql")
+

Using such mappings blocks the application from 'lazy loading', requiring you to specify loader strategies for specific queries.

u1 = s.execute(select(User)).scalars().first()
+u1.addresses
+sqlalchemy.exc.InvalidRequestError: 'User.addresses' is not available due to lazy='raise_on_sql'
+

The exception indicates that the collection must be loaded first.

u1 = s.execute(select(User).options(selectinload(User.addresses))).scalars().first()
+

The lazy="raise_on_sql" option is also wisely attempted for N:1 relationships.

Above, although the Address.user property was not loaded into Address, "raiseload" does not cause an error because the corresponding User object is in the same Session.

cf.

Preventing unwanted lazy loading with raiseload
Preventing lazy loading in relationship

+ + + diff --git a/en/tutorial/index.html b/en/tutorial/index.html new file mode 100644 index 0000000..442cfc9 --- /dev/null +++ b/en/tutorial/index.html @@ -0,0 +1,39 @@ + + + + + + Tutorial | SQLAlchemy for Python Developers + + + + + + + + + + + + + +

# Tutorial

This document is a translated and organized version of the SQLAlchemy 1.4/2.0 Tutorial (opens new window).

The original official documentation is challenging to navigate and contains an overwhelming amount of information. Furthermore, it can be quite difficult for beginners to understand.
+With this in mind, we thought of translating and organizing the SQLAlchemy Tutorial documents for easier comprehension and accessibility. The idea originated from this post (opens new window), where people gathered to work together on this project.

Over a little more than a month, we took turns each week to work on a chapter of the official Tutorial document.
+We reviewed each other's work, refining the articles and asking questions about parts we didn't understand.
+These documents are the results of such efforts and also represent the traces of our study.

There are still many imperfections, and there might be errors.
+If you find such issues, please feel free to contribute. Your participation is always welcome.

The following individuals have contributed to this project:

+ + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..36c97ce --- /dev/null +++ b/index.html @@ -0,0 +1,43 @@ + + + + + + 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +
hero

+ 파이썬 개발자를 위한 SQLAlchemy +

+ SQLAlchemy를 쉽게 정리해놓은 문서입니다. +

+ Tutorial → +

+ + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..e7c807b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/dailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/1.%20Tutorial%20Overview.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/2.%20Setting%20Up%20a%20Connection.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/3.%20Executing%20Transactions%20and%20Queries.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/4.%20Working%20with%20Database%20Metadata.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/5.3.%20Modifying%20and%20Deleting%20Rows%20Using%20Core.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/5.2.%20Inserting%20Rows%20Using%20Core.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/6.%20Manipulating%20Data%20Using%20ORM.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/dailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/5.1.%20Querying%20Rows%20Using%20Core%20and%20ORM.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/en/tutorial/7.%20Working%20with%20Related%20Objects%20Using%20ORM.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/1.%20%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC%20%EA%B0%9C%EC%9A%94.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/2.%20%EC%97%B0%EA%B2%B0%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5.2.%20Core%20%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C%20%ED%96%89%20%EC%82%BD%EC%9E%85%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/3.%20%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EA%B3%BC%20%EC%BF%BC%EB%A6%AC%20%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5.1.%20Core%EC%99%80%20ORM%20%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C%20%ED%96%89%20%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/4.%20%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%20%EB%A9%94%ED%83%80%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A1%9C%20%EC%9E%91%EC%97%85%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/5.3.%20Core%20%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C%20%ED%96%89%20%EC%88%98%EC%A0%95%20%EB%B0%8F%20%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/6.%20ORM%20%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%A1%B0%EC%9E%91%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/dailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/7.%20ORM%20%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C%20%EA%B4%80%EB%A0%A8%20%EA%B0%9C%EC%B2%B4%20%EC%9E%91%EC%97%85%ED%95%98%EA%B8%B0.htmldailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/tutorial/dailyhttps://soogoonsoogoonpythonists.github.io/sqlalchemy-for-pythonist/404.htmldaily \ No newline at end of file diff --git "a/tutorial/1. \355\212\234\355\206\240\353\246\254\354\226\274 \352\260\234\354\232\224.html" "b/tutorial/1. \355\212\234\355\206\240\353\246\254\354\226\274 \352\260\234\354\232\224.html" new file mode 100644 index 0000000..d3e153b --- /dev/null +++ "b/tutorial/1. \355\212\234\355\206\240\353\246\254\354\226\274 \352\260\234\354\232\224.html" @@ -0,0 +1,45 @@ + + + + + + 튜토리얼 개요 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# 튜토리얼 개요


# 개요

SQLAlchemy는 Python에서 데이터베이스와의 연결 및 ORM 등을 활용할 수 있도록 해주는 라이브러리 입니다.
+가령 특정 쿼리를 코드에서 실행할 수 있고, ORM 객체를 통해 데이터베이스에서의 일련의 작업들을 수행할 수 있습니다.


# 설치

SQLAlchemy는 다음처럼 설치할 수 있습니다.

$ pip install sqlalchemy
+

사용하고 있는 버전은 다음과 같습니다.

>>> import sqlalchemy
+>>> sqlalchemy.__version__  
+1.4.20
+

# 제공되는 것

SQLAlchemy는 다음처럼 2가지로 제공됩니다.

  • Core
    • 데이터베이스 도구 키트로, SQLAlchemy의 기본 아키텍처입니다.
    • 데이터베이스에 대한 연결을 관리하고, 데이터베이스 쿼리 및 결과와 상호 작용하고, SQL 문을 프로그래밍 방식으로 구성하기위한 도구를 제공합니다.
  • ORM
    • Core를 기반으로 구축되어 선택적 ORM 기능을 제공 합니다.

기본적으로 Core에 대해 먼저 이해한 후, ORM을 사용하는게 좋습니다.
+튜토리얼 역시 Core부터 설명합니다.

+ + + diff --git "a/tutorial/2. \354\227\260\352\262\260 \354\204\244\354\240\225\355\225\230\352\270\260.html" "b/tutorial/2. \354\227\260\352\262\260 \354\204\244\354\240\225\355\225\230\352\270\260.html" new file mode 100644 index 0000000..c52bb73 --- /dev/null +++ "b/tutorial/2. \354\227\260\352\262\260 \354\204\244\354\240\225\355\225\230\352\270\260.html" @@ -0,0 +1,50 @@ + + + + + + 연결 설정하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# 연결 설정하기


# 데이터베이스와 연결하기

비교적 가벼운 데이터베이스인 SQLite에 연결하는 작업을 해봅시다.
+다음처럼 해볼 수 있습니다.

>>> from sqlalchemy import create_engine
+>>> engine = create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True)
+
  • sqlalchemy.create_engine 함수를 이용하여 데이터베이스와 연결을 맺는 '엔진' 을 만듭니다.
  • 첫 번째 인자로 문자열 URL 을 넘깁니다. +
    • 일반적으로 문자열 URLdialect+driver://username:password@host:port/database 의 형태로 구성됩니다. +
      • driver 값을 주지 않으면 sqlalchemy 의 기본 설정 값이 들어가게 됩니다.
    • 여기서는 sqlite+pysqlite:///test.db문자열 URL 입니다. +
      • sqlite 의 경우 sqlite://<nohostname>/<path> 의 포맷을 따릅니다.
  • 문자열 URLsqlite:///test.db 에서 다음 정보들을 알 수 있습니다. +
    • 어떤 데이터베이스를 사용할 것인지 (dialect 라고 하며, 이 경우 sqlite 입니다)
    • 어떤 데이터베이스 API (DB와 상호작용하는 드라이버) 를 사용할 것인지 (이 경우 pysqlite 입니다)
    • 데이터베이스를 어떻게 찾을지 (이 경우 sqlite 에서 제공하는 인메모리를 사용합니다.)
  • echo 파라미터의 값을 True 를 주면 실행되는 모든 SQL을 출력해줍니다.

엔진을 만들었지만, 아직 실제로 연결을 시도한 것은 아닙니다. 실제 연결은 데이터베이스에 대해 작업을 수행하라는 요청을 처음받을 때만 발생합니다.

+ + + diff --git "a/tutorial/3. \355\212\270\353\236\234\354\236\255\354\205\230\352\263\274 \354\277\274\353\246\254 \354\213\244\355\226\211\355\225\230\352\270\260.html" "b/tutorial/3. \355\212\270\353\236\234\354\236\255\354\205\230\352\263\274 \354\277\274\353\246\254 \354\213\244\355\226\211\355\225\230\352\270\260.html" new file mode 100644 index 0000000..ea80d17 --- /dev/null +++ "b/tutorial/3. \355\212\270\353\236\234\354\236\255\354\205\230\352\263\274 \354\277\274\353\246\254 \354\213\244\355\226\211\355\225\230\352\270\260.html" @@ -0,0 +1,146 @@ + + + + + + 트랜잭션과 쿼리 실행하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# 트랜잭션과 쿼리 실행하기


# 연결 얻기

다음처럼 데이터베이스에 연결하여 쿼리를 실행할 수 있습니다.

>>> from sqlalchemy import text
+
+>>> with engine.connect() as conn:
+...     result = conn.execute(text("select 'hello world'"))
+...     print(result.all())
+
+[('hello world',)]
+
  • engine.connect() 으로 Connection (opens new window) 객체를 얻어 conn 에 담습니다. +
    • Connection 객체를 통해 데이터베이스와 상호작용할 수 있습니다.
    • with ... 구문은 하나의 트랜잭션 단위가 됩니다.
  • 트랜잭션은 자동으로 커밋되지 않습니다.
    • Connection.commit() 을 호출해야 커밋됩니다.

# 변경 사항 커밋하기

연결을 얻고, 트랜잭션을 연 뒤 데이터베이스와 상호작용하는 일들은 자동으로 커밋되지 않습니다.
+커밋을 하려면 다음처럼 Connection.commit() 을 호출해야 합니다.

>>> with engine.connect() as conn:
+...     # 테이블을 생성합니다.
+...     conn.execute(text("CREATE TABLE some_table (x int, y int)")) 
+...     # 데이터를 삽입합니다.
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 1, "y": 1}, {"x": 2, "y": 4}]
+...     )
+...     # 위 변경사항을 커밋합니다.
+...     conn.commit()
+

위 코드의 실행하면 다음과 같은 결과가 출력됩니다.

BEGIN (implicit)
+CREATE TABLE some_table (x int, y int)
+[...] ()
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+INSERT INTO some_table (x, y) VALUES (?, ?)
+[...] ((1, 1), (2, 4))
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+COMMIT
+

Engine.begin() 으로 트랜잭션 종료시 자동으로 커밋을 찍게할 수도 있습니다.

>>> with engine.begin() as conn:
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 6, "y": 8}, {"x": 9, "y": 10}]
+...     )
+... # 트랜잭션 (컨텍스트 구문)이 끝나면 커밋됩니다.
+

위 코드의 실행하면 다음과 같은 결과가 출력됩니다.

BEGIN (implicit)
+INSERT INTO some_table (x, y) VALUES (?, ?)
+[...] ((6, 8), (9, 10))
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+COMMIT
+

# 명령문 실행의 기초

다음처럼 쿼리를 실행하고 그 결과를 받아올 수 있습니다.

>>> with engine.connect() as conn:
+...     # conn.execute() 는 Result라는 객체에 내보냅니다.
+...     result = conn.execute(text("SELECT x, y FROM some_table"))
+...     for row in result:
+...         print(f"x: {row.x}  y: {row.y}")
+
+x: 1  y: 1
+x: 2  y: 4
+x: 6  y: 8
+x: 9  y: 10
+
  • Result (opens new window) 객체는 conn.execute() 가 반환해주는 "쿼리 결과"를 들고 있는 객체입니다. +
    • 링크를 눌러보면 어떤 기능을 제공하는지 볼 수 있습니다.
    • 예를 들면 Result.all() 을 통해 Row (opens new window) 객체의 리스트를 받을 수 있습니다.

ResultRow 모두 sqlalchemy에서 제공하는 객체입니다.

Result 객체로 다음처럼 각 행에 액세스할 수 있습니다.

result = conn.execute(text("select x, y from some_table"))
+
+# 튜플로 접근합니다.
+for x, y in result:
+    # ...
+    
+# 정수 인덱스로 접근합니다.
+for row in result:
+    x = row[0]
+
+# 속성 이름으로 접근합니다.
+for row in result:
+    y = row.y
+    
+# 매핑 액세스로 접근합니다.
+for dict_row in result.mappings():
+    x = dict_row['x']
+    y = dict_row['y']
+

# 쿼리에 매개 변수 전달하기

쿼리에 다음처럼 파라미터를 전달할 수 있습니다.

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         text("SELECT x, y FROM some_table WHERE y > :y"),  # 콜론 형식(:)으로 받습니다.
+...         {"y": 2}  # 사전 형식으로 넘깁니다.
+...     )
+...     for row in result:
+...        print(f"x: {row.x}  y: {row.y}")
+
+x: 2  y: 4
+x: 6  y: 8
+x: 9  y: 10
+

다음처럼 여러 개의 매개 변수를 보낼수도 있습니다.

>>> with engine.connect() as conn:
+...     conn.execute(
+...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
+...         [{"x": 11, "y": 12}, {"x": 13, "y": 14}]  # 사전의 리스트로 넘깁니다.
+...     )
+...     conn.commit()
+

위 코드는 다음과 같은 쿼리를 실행하게 됩니다.

INSERT INTO some_table (x, y) VALUES (?, ?) [...] ((11, 12), (13, 14))
+

"명령문으로 매개 변수 묶기" (opens new window) 가 공식 문서에 나오지만, 이 부분은 저도 이해가 되지 않아 넘기겠습니다.
+추후 이해하신 분은 이 문서에 기여해주시면 감사하겠습니다.


# ORM Session으로 실행

이번에는 Connection 객체가 아니라 ORM에서 제공해주는 Session 로 쿼리를 실행해봅시다.
+다음처럼 해볼 수 있습니다.

>>> from sqlalchemy.orm import Session
+
+>>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
+
+>>> # Session 객체에 Engine 객체의 인스턴스를 넘겨 데이터베이스와 상호작용할 수 있는 인스턴스를 얻습니다.
+>>> with Session(engine) as session:
+...     # Session.execute() 메서드로 쿼리를 실행합니다.
+...     result = session.execute(stmt)
+...     for row in result:
+...        print(f"x: {row.x}  y: {row.y}")
+

Session 역시 종료 시에 자동으로 커밋을하지 않습니다. 커밋을 하려면 다음처럼 직접 Session.commit() 을 호출해야 합니다.

>>> with Session(engine) as session:
+...     result = session.execute(
+...         text("UPDATE some_table SET y=:y WHERE x=:x"),
+...         [{"x": 9, "y":11}, {"x": 13, "y": 15}]
+...     )
+...     session.commit()  # 명시적으로 호출해야 합니다.
+
+ + + diff --git "a/tutorial/4. \353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244 \353\251\224\355\203\200\353\215\260\354\235\264\355\204\260\353\241\234 \354\236\221\354\227\205\355\225\230\352\270\260.html" "b/tutorial/4. \353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244 \353\251\224\355\203\200\353\215\260\354\235\264\355\204\260\353\241\234 \354\236\221\354\227\205\355\225\230\352\270\260.html" new file mode 100644 index 0000000..179cd3a --- /dev/null +++ "b/tutorial/4. \353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244 \353\251\224\355\203\200\353\215\260\354\235\264\355\204\260\353\241\234 \354\236\221\354\227\205\355\225\230\352\270\260.html" @@ -0,0 +1,161 @@ + + + + + + 데이터베이스 메타데이터로 작업하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# 데이터베이스 메타데이터로 작업하기


SQLAlchemy Core와 ORM은 파이썬 객체를 데이터베이스의 테이블과 컬럼처럼 사용할 수 있게 하기 위해서 만들어졌습니다. 이러한 것들을 데이터베이스 메타데이터로 사용할 수 있습니다.

메타데이터는 데이터를 기술하는 데이터를 설명합니다. 여기서 메타데이터는 구성된 테이블, 열, 제약 조건 및 기타 객체 정보 등을 말합니다.


# 테이블 객체를 만들고 메타데이터에 담기

관계형 데이터베이스에서는 쿼리를 통해 테이블을 만들지만, SQLAlchemy에서는 Python 객체를 통해 테이블을 만들 수 있습니다.
+SQLAlchemy 표현 언어를 시작할려면 사용할려는 데이터베이스 테이블을 Table 객체로 만들어줘야합니다.

>>> from sqlalchemy import MetaData
+>>> metadata = MetaData()  # 테이블들의 메타 정보를 담게될 객체입니다.
+>>>
+>>> from sqlalchemy import Table, Column, Integer, String
+>>> user_table = Table(
+...     'user_account',  # 데이터베이스에 저장될 table 이름입니다.
+...     metadata,
+...     Column('id', Integer, primary_key=True),  # 이 테이블에 들어갈 컬럼입니다.
+...     Column('name', String(30)),
+...     Column('fullname', String),
+... )
+
  • Table 객체를 통해 데이터베이스 테이블을 만들 수 있습니다.
  • Column을 통해 테이블의 컬럼을 구현합니다. +
    • 기본적으로 Column(컬럼 이름, 데이터 유형) 와 같이 정의합니다.

Table 인스턴스를 만들고나면 다음처럼 만들어진 컬럼 정보를 알 수 있습니다.

>>> user_table.c.name
+Column('name', String(length=30), table=<user_account>)
+
+>>> user_table.c.keys()
+['id', 'name', 'fullname']
+

# 단순 제약 선언하기

우리는 위의 user 테이블을 만드는 코드에서 Column('id', Integer, primary_key=True) 구문을 보았습니다.
+이는 id 컬럼을 기본키로 둔다고 선언하는 것입니다.
+기본키는 암시적으로 PrimaryKeyConstraint 객체에 구조로 선언되어있습니다. 이는 다음처럼 확인할 수 있습니다.

>>> user_table.primary_key
+PrimaryKeyConstraint(Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False))
+

기본키와 더불어 외래키도 다음처럼 선언할 수 있습니다.

>>> from sqlalchemy import ForeignKey
+>>> address_table = Table(
+...     "address",
+...     metadata,
+...     Column('id', Integer, primary_key=True),
+...     Column('user_id', ForeignKey('user_account.id'), nullable=False),  # ForeignKey 객체로 외래 키를 선언합니다.
+...     Column('email_address', String, nullable=False)
+... )
+
  • ForeignKey('테이블 이름.외래 키') 형태로 외래 키 컬럼을 선언할 수 있습니다. +
    • 이 때 Column 객체의 데이터타입을 생략할 수 있습니다. 데이터타입은 외래 키에 해당하는 컬럼을 찾아서 자동으로 추론됩니다.
  • 따로 설명하지 않았지만, nullable=False 파라미터와 값을 넘김으로써 컬럼에 NOT NULL 제약 조건을 선언할 수 있습니다.

# 데이터베이스에 적용하기

지금까지 SQLAlchemy로 데이터베이스 테이블을 선언했습니다. 이제 이렇게 선언한 테이블이 실제 데이터베이스에 생성되도록 해봅시다.
+다음처럼 metadata.create_all() 을 실행합니다.

>>> metadata.create_all(engine)
+
+# 위 코드는 `metadata` 인스턴스에 기록된 모든 테이블들을 생성합니다.  
+# 결과적으로는 아래 쿼리를 실행하게 됩니다.
+
+BEGIN (implicit)
+PRAGMA main.table_...info("user_account")
+...
+PRAGMA main.table_...info("address")
+...
+CREATE TABLE user_account (
+    id INTEGER NOT NULL,
+    name VARCHAR(30),
+    fullname VARCHAR,
+    PRIMARY KEY (id)
+)
+...
+CREATE TABLE address (
+    id INTEGER NOT NULL,
+    user_id INTEGER NOT NULL,
+    email_address VARCHAR NOT NULL,
+    PRIMARY KEY (id),
+    FOREIGN KEY(user_id) REFERENCES user_account (id)
+)
+...
+COMMIT
+

# ORM 방식으로 테이블 메타데이터 정의하기

위의 데이터베이스 구조를 만들고 제약조건을 똑같이 사용하지만, 이번에는 ORM 방식으로 진행해보겠습니다.


# 레지스트리 설정하기

먼저 다음처럼 registry 객체를 만듭니다.

>>> from sqlalchemy.orm import registry
+>>> mapper_registry = registry()
+

registery 객체는 MetaData 객체를 포함하고 있습니다.

>>> mapper_registry.metadata
+MetaData()
+

이제 다음을 실행합니다.

>>> Base = mapper_registry.generate_base()
+

위 과정을 다음처럼 declarative_base 로 한 번에 할 수 있습니다.

>>> from sqlalchemy.orm import declarative_base
+>>> Base = declarative_base()
+

# ORM 객체 선언하기

Base 객체를 상속받는 하위 객체를 정의함으로써 ORM 방식으로 데이터베이스의 테이블을 선언할 수 있습니다.

>>> from sqlalchemy.orm import relationship
+>>> class User(Base):
+...     __tablename__ = 'user_account'  # 데이터베이스에서 사용할 테이블 이름입니다.
+...
+...     id = Column(Integer, primary_key=True)
+...     name = Column(String(30))
+...     fullname = Column(String)
+...
+...     addresses = relationship("Address", back_populates="user")
+...
+...     def __repr__(self):
+...        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"
+
+>>> class Address(Base):
+...     __tablename__ = 'address'
+...
+...     id = Column(Integer, primary_key=True)
+...     email_address = Column(String, nullable=False)
+...     user_id = Column(Integer, ForeignKey('user_account.id'))
+...
+...     user = relationship("User", back_populates="addresses")
+...
+...     def __repr__(self):
+...         return f"Address(id={self.id!r}, email_address={self.email_address!r})"
+

User, Address 객체는 Table 객체를 포함합니다.
+다음처럼 __table__ 속성을 통해 확인할 수 있습니다.

>>> User.__table__
+Table('user_account', MetaData(),
+    Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False),
+    Column('name', String(length=30), table=<user_account>),
+    Column('fullname', String(), table=<user_account>), schema=None)
+

# ORM 객체 생성하기

위에서 정의한 뒤, 다음처럼 ORM 객체를 생성할 수 있습니다.

>>> sandy = User(name="sandy", fullname="Sandy Cheeks")
+>>> sandy
+User(id=None, name='sandy', fullname='Sandy Cheeks')
+

# 데이터베이스에 적용하기

이제 다음처럼 ORM으로 선언한 테이블을 실제로 데이터베이스에 적용되도록 할 수 있습니다.

>>> mapper_registry.metadata.create_all(engine)
+>>> Base.metadata.create_all(engine)
+

# 기존 데이터베이스의 테이블을 ORM 객체로 불러오기

위의 모든 방법들은 테이블을 직접 선언하지않고, 데이터베이스에 테이블을 가져오는 방법이 있습니다.
+코드는 아래와 같습니다.

>>> some_table = Table("some_table", metadata, autoload_with=engine)
+
+BEGIN (implicit)
+PRAGMA main.table_...info("some_table")
+[raw sql] ()
+SELECT sql FROM  (SELECT * FROM sqlite_master UNION ALL   SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'
+[raw sql] ('some_table',)
+PRAGMA main.foreign_key_list("some_table")
+...
+PRAGMA main.index_list("some_table")
+...
+ROLLBACK
+

이제 다음과 같이 사용할 수 있습니다.

>>> some_table
+Table('some_table', MetaData(),
+    Column('x', INTEGER(), table=<some_table>),
+    Column('y', INTEGER(), table=<some_table>),
+    schema=None)
+
+ + + diff --git "a/tutorial/5.1. Core\354\231\200 ORM \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\241\260\355\232\214\355\225\230\352\270\260.html" "b/tutorial/5.1. Core\354\231\200 ORM \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\241\260\355\232\214\355\225\230\352\270\260.html" new file mode 100644 index 0000000..680cff5 --- /dev/null +++ "b/tutorial/5.1. Core\354\231\200 ORM \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\241\260\355\232\214\355\225\230\352\270\260.html" @@ -0,0 +1,641 @@ + + + + + + Core와 ORM 방식으로 행 조회하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# Core와 ORM 방식으로 행 조회하기


이번 챕터에서는 SQLAlchemy에서 가장 자주 쓰이는 Select에 대해서 다룹니다.


# select() 를 통한 SQL 표현식 구성

select() 생성자는 insert() 생성자와 같은 방식으로 쿼리문을 만들 수 있습니다.

>>> from sqlalchemy import select
+>>> stmt = select(user_table).where(user_table.c.name == 'spongebob')
+>>> print(stmt)
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1
+"""
+

마찬가지로 쿼리문을 실행시키 위해 같은 레벨의 SQL 생성자들(select, insert, update, create등)처럼 Connection.execute() 메서드에 쿼리를 넣어 실행시킬 수 있습니다.

>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         print(row)
+(1, 'spongebob', 'Spongebob Squarepants')
+

한편 ORM을 사용해 select 쿼리문을 실행시키고 싶을 때는 Session.exeucte()를 사용해야합니다. +결과는 방금 전의 예제와 마찬가지로 Row객체를 반환하지만 이 객체는 이전의 튜토리얼, 4. 데이터베이스 메타데이터로 작업하기 (opens new window)에서 +정의했던 User객체를 포함하고 있습니다.

>>> stmt = select(User).where(User.name == 'spongebob')
+# User 객체의 인스턴스 안에 있는 각 row 들을 출력
+>>> with Session(engine) as session:
+...     for row in session.execute(stmt):
+...         print(row)
+(User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)
+

# FROM절과 컬럼 세팅하기

select()함수는 위치인자로 Column이나 Table등을 포함한 다양한 객체들을 받을 수 있습니다. +이러한 인자 값들은 select()함수의 반환 값, 즉 SQL쿼리문으로 표현 될 수있고 FROM절을 세팅해주기도 합니다.

>>> print(select(user_table))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+"""
+

각각의 컬럼들을 Core를 이용해 조회하려면 Table.c접근자를 통해 Column객체에 접근하면 됩니다.

>>> print(select(user_table.c.name, user_table.c.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

# ORM 엔터티 및 열 조회

SQL 쿼리를 SqlAlchemy에서 구현할 때 테이블이나 컬럼을 표현하기 위해 User객체같은 ORM 엔터티나, User.name과 같이 컬럼이 매핑된 속성(어트리뷰트)을 사용할 수 있습니다. +아래의 예제는 User엔터티를 조회하는 예제이지만 사실은 +user_table 를 사용했을 때와 결과가 동일합니다.

>>> print(select(User))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+"""
+

위의 예제의 쿼리를 ORM Session.exeucte()를 통해 똑같이 실행 할 수 있는데, 이때는 User엔터티를 조회하는 것과 user_info를 조회하는 것에 차이가 있습니다. +user_info를 조회하든 User엔티티를 조회 하든 둘 다Row객체가 반환되지만 User엔터티를 조회 할 경우에는 +User인스턴스를 포함한 Row 객체가 반환됩니다.

여기서 user_tableUser이전 챕터에서 만들어졌는데, +user_tableTable 객체이고 +UserBase 객체를 상속받아Table객체를 포함하고 있는 엔터티입니다.

>>> with Session(engine) as session:
+...     row = session.execute(select(User)).first()
+...     print(row)
+(User(id=1, name='spongebob',fullname='Spongebob Squarepants'),)
+

한편 객체 속성(class-bound attributes)을 사용해 원하는 컬럼들을 조회할 수도 있습니다.

>>> print(select(User.name, User.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

객체 속성을 Session.execute()을 이용해 조회 할 경우에는 +인자로 보내진 객체 속성의 값(컬럼 값)이 아래와 같이 반환됩니다.

>>> with Session(engine) as session:
+...	row = session.execute(select(User.name, User.fullname)).first()
+...	print(row)
+('spongebob', 'Spongebob Squarepants')
+

이러한 방법들은 믹스인 방법으로 섞어서 사용할 수도 있습니다.

>>> session.execute(
+...     select(User.name, Address).
+...     where(User.id==Address.user_id).
+...     order_by(Address.id)
+... ).all()
+[('spongebob', Address(id=1, email_address='spongebob@sqlalchemy.org')),
+('sandy', Address(id=2, email_address='sandy@sqlalchemy.org')),
+('sandy', Address(id=3, email_address='sandy@squirrelpower.org'))]
+

# 라벨링된 SQL 표현식 조회하기

SELECT name AS username FROM user_account 쿼리를 실행 할 경우 아래와 같은 결과가 나옵니다.

username
patrick
sandy
spongebob

여기서 우리는 name컬럼의 이름을 username으로 라벨링 해줬기 때문에 상단 컬럼에 username 이 뜨는 건데요. +이러한 기능을 SQLAlchemy의 ColumnElement.label()함수를 이용해 동일하게 구현할 수 있습니다.

>>> from sqlalchemy import func, cast
+>>> stmt = (
+...     select(
+...         ("Username: " + user_table.c.name).label("username"),  # 이렇게 라벨링 합니다.
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         print(f"{row.username}")  # 라벨링한 부분은 이렇게 접근할 수 있습니다.
+Username: patrick
+Username: sandy
+Username: spongebob
+

# 문자열 컬럼 조회하기

보통 Select객체나 select() 생성자를 이용 해 컬럼을 조회하는 경우가 많지만 가끔은 임의로 문자열과 함께 컬럼을 조회 해야하는 경우가 있습니다. 이번 섹션에서는 이러한 스트링 데이터를 조회 하는 방법에 다룹니다.

text() 생성자는 이전 챕터 3. 트랜잭션 및 데이터베이스API 작업 (opens new window)에서 한 번 소개가 되었는데요, 이 text()생성자안에 SELECT구문을 곧바로 넣어 사용할 수도 있었습니다.

한편 우리는 SELECT 'some_phrase', name FROM user_account 와 같은 쿼리를 실행시키고 싶다고 생각해봅시다. +이 때, some_phrase은 문자열이기 때문에 꼭 큰 따옴표나 작은 따옴표로 감싸줘야합니다. 그리고 그 결과, 출력물에도 어쩔 수 없이 작은 따옴표가 전부 붙어서 나옵니다.

>>> from sqlalchemy import text
+>>> stmt = (
+...     select(
+...         text("'some phrase'"), user_table.c.name
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     print(conn.execute(stmt).all())
+[('some phrase', 'patrick'), ('some phrase', 'sandy'), ('some phrase', 'spongebob')]
+

그래서 보통은 text()보다 literal_column()을 사용해 작은 따옴표가 결과물에 붙어져서 나오는 문제를 해결할 수 있습니다.
+여기에서 textliteral_column()은 거의 비슷하지만 literal_column()은 명시적으로 컬럼을 의미하고, 서브쿼리나 다른 SQL 표현식에서 쓰일 수 있게 라벨링도 할 수 있습니다.

>>> from sqlalchemy import literal_column
+>>> stmt = (
+...     select(
+...         literal_column("'some phrase'").label("p"), user_table.c.name
+...     ).order_by(user_table.c.name)
+... )
+>>> with engine.connect() as conn:
+...     for row in conn.execute(stmt):
+...         print(f"{row.p}, {row.name}")
+some phrase, patrick
+some phrase, sandy
+some phrase, spongebob
+
+

# WHERE절

SQLAlchemy를 사용하면 Python 연산자를 사용하여 name = 'thead'또는user_id > 10` 인 데이터만 출력하는 쿼리를 쉽게 작성할 수 있습니다.

>>> print(user_table.c.name == 'squidward')
+user_account.name = :name_1
+
+>>> print(address_table.c.user_id > 10)
+address.user_id > :user_id_1
+

WHERE절을 만들기 위해 Select.where()메서드안에 인자값을 넣어 사용할 수도 있습니다.

>>> print(select(user_table).where(user_table.c.name == 'squidward'))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1
+"""
+

WHERE 절을 통한 JOIN을 구현해야 할 때, 아래와 같이 작성 가능합니다.

>>> print(
+...         select(address_table.c.email_address).
+...         where(user_table.c.name == 'squidward').
+...         where(address_table.c.user_id == user_table.c.id)
+... )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE user_account.name = :name_1 AND address.user_id = user_account.id
+"""
+
+# 위와 같은 표현이지만, 아래처럼 where()메서드의 파라미터로 넘기는 방식도 가능합니다.
+>>> print(
+        select(address_table.c.email_address).
+...         where(
+...             user_table.c.name == 'squidward',
+...             address_table.c.user_id == user_table.c.id
+...         )
+... )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE user_account.name = :name_1 AND address.user_id = user_account.id
+"""
+

and_(), or_()등의 연결 구문도 구현가능합니다.

>>> from sqlalchemy import and_, or_
+>>> print(
+...     select(Address.email_address).
+...         where(
+...             and_(
+...                 or_(User.name == 'squidward', User.name == 'sandy'),
+...                 Address.user_id == User.id
+...             )
+...         )
+...  )
+"""
+SELECT address.email_address
+FROM address, user_account
+WHERE (user_account.name = :name_1 OR user_account.name = :name_2)
+AND address.user_id = user_account.id
+"""
+

단순히 같은지, 아닌지 비교하는 경우(equality) Select.filter_by()도 자주 사용됩니다.

>>> print(
+...     select(User).filter_by(name='spongebob', fullname='Spongebob Squarepants')
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = :name_1 AND user_account.fullname = :fullname_1
+"""
+

# FROM절과 JOIN 명시하기

앞에서 언급했지만 FROM절은 따로 명시하지 않아도 select()메서드의 인자에 넣은 컬럼들로 자동 세팅이 됩니다.

# 따로 FROM 절을 명시하지 않았지만 FROM 절이 세팅되어 출력됩니다.
+>>> print(select(user_table.c.name))
+"""
+SELECT user_account.name
+FROM user_account
+"""
+

만약 select()의 위치 인자로 서로 다른 두 개의 테이블을 참조하는 컬럼을,(컴마)로 구분지어 넣을 수도 있습니다

>>> print(select(user_table.c.name, address_table.c.email_address))
+"""
+SELECT user_account.name, address.email_address
+FROM user_account, address
+"""
+

서로 다른 두 개의 테이블을 JOIN조인하고 싶다면, 이용할 수 있는 메서드가 두 가지가 있는데요, +하나는 Select.join()메서드로 명시적으로 JOIN 할 왼쪽에 들어갈 테이블, 오른쪽에 들어 갈 테이블을 직접 지정할 수 있습니다

>>> print(
+...     select(user_table.c.name, address_table.c.email_address).
+...     join_from(user_table, address_table)
+... )
+"""
+SELECT user_account.name, address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

다른 하나는 Select.join()메서드로 오른쪽에 들어갈 테이블만 명시적으로 적어주고 +나머지 테이블은 암시적으로 컬럼을 선택할 때 참조하게 합니다.

# 위와 동일한 표현이지만, 조인할 왼쪽 테이블(user_table)은 암시적으로 표현됩니다.
+>>> print(
+...     select(user_table.c.name, address_table.c.email_address).
+...     join(address_table)
+... )
+"""
+SELECT user_account.name, address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

또는 JOIN 하는 두 개의 테이블을 조금 더 명시적으로 작성하고 싶거나 FROM절에 명시적인 추가 옵션을 주고 싶다면 +아래와 같이 작성 할 수도 있습니다.

>>> print(
+...     select(address_table.c.email_address).
+...     select_from(user_table).join(address_table)
+... )
+"""
+SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

Select.select_from()을 사용하는 또 다른 경우는 우리가 조회하고 싶은 컬럼들을 통해 암시적으로 FROM 절을 세팅할 수 없는 경우입니다. 예를 들면 일반적인 SQL 쿼리문에서 count(*)를 조회하기 위해선 SQLAlchemy의 sqlalchemy.sql.expression.func를 사용해야합니다.

>>> from sqlalchemy import func
+>>> print(select(func.count('*')).select_from(user_table))
+"""
+SELECT count(:count_2) AS count_1
+FROM user_account
+"""
+

# On절 세팅하기

그런데 뭔가 이상한게 있었죠? +사실 이 전의 예제에서 Select.select_from()이나 select.join()을 이용해 두 테이블을 JOIN할 때 암시적으로 ON절이 세팅되었답니다.
+왜 자동으로 ON 절이 세팅 됐냐면, user_table객체와, address_table 객체가 ForeignKeyConstraint, 즉 외부키 제약을 갖고 있어서 자동으로 세팅이 된 것입니다.

만약에 Join의 대상인 두 개의 테이블에서 이러한 제약 key가 없을 경우 ON절을 직접 지정해야 합니다. 이러한 기능은 Select.join()Select.join_from()메서드에 파라미터 전달을 통해 명시적으로 ON절을 세팅할 수 있습니다.

>>> print(
+...     select(address_table.c.email_address).
+...     select_from(user_table).
+...     join(address_table, user_table.c.id == address_table.c.user_id)
+... )
+"""
+SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+

# OUTER, FULL Join

SQLAlchemy에서 LEFT OUTER JOIN, FULL OUTER JOIN를 구현하려면 +Select.join()Select.join_from()메서드의 키워드 인자로 Select.join.isouter, +Select.join.full를 사용할 수 있습니다.

LEFT OUTER JOIN을 구현 한 경우,

>>> print(
+...     select(user_table).join(address_table, isouter=True)
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account LEFT OUTER JOIN address ON user_account.id = address.user_id
+"""
+

FULL OUTER JOIN을 구현 한 경우,

>>> print(
+...     select(user_table).join(address_table, full=True)
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account FULL OUTER JOIN address ON user_account.id = address.user_id
+"""
+

# ORDER BY, GROUP BY, HAVING

  • ORDER BY절은 SELECT절에서 조회한 행들의 순서를 설정할 수 있습니다.
  • GROUP BY절은 그룹 함수로 조회된 행들을 특정한 컬럼을 기준으로 그룹을 만듭니다.
  • HAVINGGROUP BY절을 통해 생성된 그룹에 대해 조건을 겁니다.

# ORDER BY

Select.order_by()를 이용해 ORDER BY기능을 구현할 수 있습니다. 이때 위치 인자 값으로 Column객체나 이와 비슷한 객체들을 받을 수 있습니다.

>>> print(select(user_table).order_by(user_table.c.name))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.name
+"""
+

오름차순, 내림차순은 +ColumnElement.asc(), ColumnElement.desc() 제한자를 통해 구현 할 수 있습니다. +아래 예제는 user_account.fullname컬럼 기준으로 내림 차순으로 정렬합니다.

>>> print(select(User).order_by(User.fullname.desc()))
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.fullname DESC
+"""
+

# 그룹함수 : GROUP BY, Having

SQL에서는 집계함수를 이용해 조회 된 여러개의 행들을 하나의 행으로 합칠 수도 있습니다. +집계함수의 예로 COUNT(), SUM(), AVG()등이 있습니다.

SQLAlchemy에서는 func라는 네임스페이스를 이용해 SQL함수를 제공하는데, 이 func는 +SQL함수의 이름이 주어지면 Function인스턴스를 생성합니다.

아래의 예제에서는 user_account.id컬럼을 SQL COUNT()함수에 렌더링 하기 위해 count()함수를 호출합니다.

>>> from sqlalchemy import func
+>>> count_fn = func.count(user_table.c.id)
+>>> print(count_fn)
+"""
+count(user_account.id)
+"""
+

SQL 함수에 관해서는 SQL 함수 다루기에서 더 자세히 설명되어 있습니다.

다시 설명하자면

  • GROUP BY는 조회된 행들을 특정 그룹으로 나눌 때 필요한 함수입니다. +만약에 SELECT 절에서 몇 개의 컬럼을 조회 할 경우 SQL에서는 직,간접적으로 이 컬럼들이 기본키(primary key)를 기준으로 +GROUP BY에 종속되도록 합니다.
  • HAVINGGROUP BY로 만들어진 그룹들에 대해 조건을 적용 할 경우 필요합니다.(그룹에 대해 조건을 걸기 때문에 WHERE절과 비슷합니다)

SQLAlchemy에서는 Select.group_by()Select.having()를 이용해 GROUP BYHAVING을 구현 할 수 있습니다.

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         select(User.name, func.count(Address.id).label("count")).
+...         join(Address).
+...         group_by(User.name).
+...         having(func.count(Address.id) > 1)
+...     )
+...     print(result.all())
+""" 위 구문은 아래 SQL을 표현합니다.
+SELECT user_account.name, count(address.id) AS count
+FROM user_account JOIN address ON user_account.id = address.user_id GROUP BY user_account.name
+HAVING count(address.id) > ?
+[...] (1,)
+"""
+
+[('sandy', 2)]
+

# 별칭을 통해 그룹화 또는 순서 정렬하기

어떤 데이터 베이스 백엔드에서는 집계함수를 사용해 테이블을 조회 할 때 ORDER BY 절이나 GROUP BY절에 이미 명시된 집계함수를 다시 명시적으로 사용하지 않는 것이 중요합니다.

# NOT GOOD
+SELECT id, COUNT(id) FROM user_account GROUP BY id ORDER BY count(id)
+
+# CORRECT
+SELECT id, COUNT(id) as cnt_id FROM user_account GROUP BY id ORDER BY cnt_id
+

따라서 별칭을 통해 ORDER BYGROUP BY를 구현하려면 +Select.order_by() 또는 Select.group_by()메서드에 인자로 사용 할 별칭을 넣어주면 됩니다.
+여기에 사용된 별칭이 먼저 렌더링 되는건 아니고 컬럼절에 사용된 별칭이 먼저 렌더링 됩니다. 그리고 렌더링된 별칭이 나머지 쿼리문에서 매칭되는게 없다면 에러가 발생합니다.

>>> from sqlalchemy import func, desc
+>>> # 컬럼에도 num_addresses 별칭이 들어가고 order_by에도 같은 별칭이 들어갑니다.
+>>> stmt = select(
+...         Address.user_id,
+...         func.count(Address.id).label('num_addresses')).\
+...         group_by("user_id").order_by("user_id", desc("num_addresses"))
+>>> print(stmt)
+"""
+SELECT address.user_id, count(address.id) AS num_addresses
+FROM address GROUP BY address.user_id ORDER BY address.user_id, num_addresses DESC
+"""
+

# 별칭 사용하기

여러개의 테이블을 JOIN을 이용해 조회 할 경우 쿼리문에서 테이블 이름을 여러번 적어줘야 하는 경우가 많습니다. +SQL에서는 이러한 문제를 테이블 명이나 서브 쿼리에 별칭(aliases)를 지어 반복되는 부분을 줄일 수 있습니다.

한편 SQLAlchemy에서는 이러한 별칭들은 Core의 FromCaluse.alias()함수를 이용해 구현 할 수 있습니다. +Table객체 네임스페이스 안에 Column객체가 있어 Table.c로 컬럼명에 접근할 수 있었는데요.

print(select(user_table.c.name, user_table.c.fullname))
+"""
+SELECT user_account.name, user_account.fullname
+FROM user_account
+"""
+

Alias객체 네임스페이스 안에도 Column객체가 있어 Alias.c로 컬럼에 접근 가능합니다.

>>> # user_alias_1과 user_alias_2 모두 Alias객체입니다.
+>>> user_alias_1 = user_table.alias(‘table1’) 
+>>> user_alias_2 = user_table.alias(‘table2’)
+>>> # 방금 만든 테이블 별명으로 컬럼에 접근하려면 Alias.c.컬럼명으로 접근해야합니다.
+>>> print(
+...     select(user_alias_1.c.name, user_alias_2.c.name).
+...     join_from(user_alias_1, user_alias_2, user_alias_1.c.id > user_alias_2.c.id)
+... )
+
+"""
+SELECT table1.name, table2.name AS name_1 
+FROM user_account AS table1 JOIN user_account AS table2 ON table1.id > table2.id
+"""
+

# ORM 엔티티 별칭

ORM도 FromClause.alias()메서드와 비슷한 aliased()함수가 존재합니다.

이 ORM aliased()는 ORM의 기능을 유지하면서 원래 매핑된 Table객체에 내부적으로 Alias객체를 생성합니다.

여기서 AddressUser객체는 이전 챕터에서 만들어졌는데, +두 객체 모두 Base 객체를 상속받아Table객체를 포함하고 있는 엔터티입니다.

>>> user_alias_1 = user_table.alias()
+>>> user_alias_2 = user_table.alias()
+>>> # 예제에서는 User나 Address엔터티에 적용됩니다.  
+>>> print(
+...     select(User).
+...     join_from(User, address_alias_1).
+...     where(address_alias_1.email_address == 'patrick@aol.com').
+...     join_from(User, address_alias_2).
+...     where(address_alias_2.email_address == 'patrick@gmail.com')
+... )
+"""
+SELECT user_account.id, user_account.name, user_account.fullname 
+FROM user_account JOIN address AS address_1 ON user_account.id = address_1.user_id JOIN address AS address_2 ON user
+"""
+

# 서브쿼리와 CTE

이 섹션에서는 일반적으로 SELECT의 FROM 절에 있는 서브 쿼리에 대해 설명합니다. 서브쿼리와 유사한 방식으로 사용되지만 추가 기능이 포함된 CTE도 다룹니다.

CTE(Common Table Expression)는 동일 쿼리 내에서 여러번 참조할 수 있게 하는 쿼리 내 임시 결과 집합입니다. 이 글 (opens new window)에 CTE에 대해 잘 설명되어 있으니, 잘 모르시겠는 분들은 참고하시면 좋습니다.

SQLAlchemy는 Subquery 개체를 +Select.subquery()사용하여 서브 쿼리를 나타내고 Select.cte() 를 사용하여 CTE를 나타냅니다.

>>> subq = select(
+...     func.count(address_table.c.id).label("count"),
+...     address_table.c.user_id
+... ).group_by(address_table.c.user_id).subquery()
+>>> print(subq)
+"""
+SELECT count(address.id) AS count, address.user_id
+FROM address GROUP BY address.user_id
+"""
+
+>>> stmt = select(
+...    user_table.c.name,
+...    user_table.c.fullname,
+...    subq.c.count
+... ).join_from(user_table, subq) # ON절은 두 개의 테이블이 이미 foreigh key로 제약이 걸려있어 자동 바인딩된다.
+>>> print(stmt)
+"""
+SELECT user_account.name, user_account.fullname, anon_1.count
+FROM user_account JOIN (SELECT count(address.id) AS count, address.user_id AS user_id
+FROM address GROUP BY address.user_id) AS anon_1 ON user_account.id = anon_1.user_id
+"""
+

# 계층 쿼리

SQLAlchemy에서 CTE 구문을 사용하는 방법은 서브 쿼리 구문이 사용되는 방식과 거의 동일합니다. 대신 Select.subquery() 메서드의 호출을 Select.cte()를 사용하도록 변경하여 결과 객체를 FROM 요소로 사용할 수 있습니다.

>>> subq = select(
+...     func.count(address_table.c.id).label("count"),
+...     address_table.c.user_id
+... ).group_by(address_table.c.user_id).cte()
+
+>>> stmt = select(
+...    user_table.c.name,
+...    user_table.c.fullname,
+...    subq.c.count
+... ).join_from(user_table, subq)
+
+>>> print(stmt)
+"""
+WITH anon_1 AS
+(SELECT count(address.id) AS count, address.user_id AS user_id
+FROM address GROUP BY address.user_id)
+ SELECT user_account.name, user_account.fullname, anon_1.count
+FROM user_account JOIN anon_1 ON user_account.id = anon_1.user_id
+"""
+

# ORM 엔티티 서브쿼리, CTE

여기서는 aliased()Subquery, CTE서브 쿼리에 대해 동일한 작업을 수행하는 과정을 확인할 수 있습니다.

>>> subq = select(Address).where(~Address.email_address.like('%@aol.com')).subquery()
+>>> address_subq = aliased(Address, subq)
+>>> stmt = select(User, address_subq).join_from(User, address_subq).order_by(User.id, address_subq.id)
+>>> with Session(engine) as session:
+...     for user, address in session.execute(stmt):
+...         print(f"{user} {address}")
+
+""" 위 구문은 아래 쿼리를 표현합니다.
+SELECT user_account.id, user_account.name, user_account.fullname,
+anon_1.id AS id_1, anon_1.email_address, anon_1.user_id
+FROM user_account JOIN
+(SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id
+FROM address
+WHERE address.email_address NOT LIKE ?) AS anon_1 ON user_account.id = anon_1.user_id
+ORDER BY user_account.id, anon_1.id
+[...] ('%@aol.com',)
+"""
+
+User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
+

아래는 CTE생성자를 이용해 위와 같은 사용하는 예제입니다

>>> cte = select(Address).where(~Address.email_address.like('%@aol.com')).cte()
+>>> address_cte = aliased(Address, cte)
+>>> stmt = select(User, address_cte).join_from(User, address_cte).order_by(User.id, address_cte.id)
+>>> with Session(engine) as session:
+...     for user, address in session.execute(stmt):
+...         print(f"{user} {address}")
+
+User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
+User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
+

# 스칼라 서브 쿼리, 상호연관 쿼리

스칼라 서브 쿼리에 대해 설명하기전 잠시 SQL에서 서브 쿼리에 대해 이야기 하겠습니다. 출처:바이헨 블로그 (opens new window)

  • "서브쿼리"란 하나의 SQL문에 속한 SELECT문을 말하고 서브 쿼리의 바깥 쪽에 있는 SQL문을 "메인 쿼리"라고 합니다.

이때 서브쿼리의 종류는 메인 쿼리 컬럼을 참조 여부, 서브쿼리의 선언 위치, 서브 쿼리 실행 결과 ROW수에 따라 종류가 나눠집니다

  • 메인 쿼리 컬럼 참조 여부에 따른 구분 +
    • 상호 연관 서브쿼리 : 서브쿼리가 메인 쿼리 컬럼을 참조
    • 비상호 연관 서브 쿼리: 서브쿼리가 메인 쿼리의 컬럼을 참조하지 않고 독립적으로 수행하고 메인쿼리에 정보를 전달할 목적으로 사용됩니다.
  • 서브쿼리 선언 위치에 따른 구분 +
    • 스칼라 서브 쿼리 : SELECT 문의 컬럼자리에 오는 서브 쿼리(상호 연관 서브쿼리)
    • 인라인 뷰 : FROM절 자리에 오는 서브 쿼리 (상호 연관 서브 쿼리)
    • 중첩 서브 쿼리 : Where절 자리에 오는 서브 쿼리 (비상호 연관 서브 쿼리)
  • 서브 쿼리 실행 결과 ROW수에 따른 구분 +
    • 단일행 서브쿼리(서브 쿼리 연산결과 ROW1개)
    • 단중행 서브쿼리(서브 쿼리 연산결과 ROW2개이상):IN, ANY, ALL, EXSITS

SQLAlchemy에서 스칼라 서브 쿼리는 ColumnElement객체의 일부인 ScalarSelect를 사용하는 방면 일반 서브 쿼리는FromClause객체에 있는 Subquery를 사용합니다.

스칼라 서브쿼리는 앞에서 설명했던 그룹 합수 (opens new window)와 같이 쓰이고는 합니다.

# Select.scalar_subquery()를 이용해 구현한 스칼라 서브 쿼리
+>>> subq = select(func.count(address_table.c.id)).
+...             where(user_table.c.id == address_table.c.user_id).
+...             scalar_subquery()
+>>> print(subq) #ScalarSelect객체
+"""
+(SELECT count(address.id) AS count_1
+FROM address, user_account
+WHERE user_account.id = address.user_id)
+"""
+

스칼라 서브 쿼리가 user_accountaddress를 FROM절에서 렌더링하지만 +메인쿼리에 있는 user_account테이블이 있어서 +스칼라 서브 쿼리에서는 user_account 테이블을 렌더링하지 않습니다.

>>> stmt = select(user_table.c.name, subq.label("address_count"))
+>>> print(stmt)
+"""
+SELECT user_account.name, (SELECT count(address.id) AS count_1
+FROM address
+WHERE user_account.id = address.user_id) AS address_count
+FROM user_account
+"""
+

한편 상호 연관 쿼리를 작성 할 때 테이블 간의 연결이 모호해질 수도 있습니다.

튜토리얼에 나와있는 상호 연관쿼리 예제는 제가 이해하지 못했습니다. +잘 아시는분은 이문서에 기여 부탁드립니다.


# UNION, UNION ALL 연산자들

SQL에서는 UNION, UNION ALL등으로 두 개의 SELECT문을 합치는 것을 의미합니다.
+아래와 같이 쿼리문을 실행 할 수도 있습니다.

SELECT id FROM user_account
+union 
+SELECT email_address FROM address
+

그 외에도 집합 연산인 INTERSECT(교집합), EXCEPT(차집합)도 SQL에서 지원합니다.
+SQLAlchemy에서 Select 객체에 대하여 union(), intersect(), except_() 혹은 +union_all(), intersect_all(), except_all()을 지원합니다.

이러한 함수들의 반환 값은 CompoundSelect인데 Select와 비슷하게 쓰일 수 있는 객체이지만 더 적은 메서드를 갖고 있습니다.
union_all()의 반환값 CompoundSelect객체는 Connection.execute()로 실행될 수 있습니다.

>>> from sqlalchemy import union_all
+>>> stmt1 = select(user_table).where(user_table.c.name == 'sandy')
+>>> stmt2 = select(user_table).where(user_table.c.name == 'spongebob')
+>>> u = union_all(stmt1, stmt2) #u는 CompoundSelect 객체입니다.
+>>> with engine.connect() as conn:
+...     result = conn.execute(u)
+...     print(result.all())
+
+[(2, 'sandy', 'Sandy Cheeks'), (1, 'spongebob', 'Spongebob Squarepants')]
+

Subquery객체를 만들기 위해 SelectSelectBase.subquery()메서드를 제공하는 것처럼 +CompoundSelect객체를 서브 쿼리로 비슷한 방식으로 사용 할 수 있습니다.

>>> u_subq = u.subquery()
+>>> stmt = (
+...     select(u_subq.c.name, address_table.c.email_address).
+...     join_from(address_table, u_subq).
+...     order_by(u_subq.c.name, address_table.c.email_address)
+... )
+>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[('sandy', 'sandy@sqlalchemy.org'), ('sandy','sandy@squirrelpower.org'), 
+('spongebob', 'spongebob@sqlalchemy.org')]
+

# EXISTS 서브쿼리들

SQLAlchemy는 SelectBase.exists()메서드를 통해 Exists객체를 만들어 EXISTS 구문을 구현합니다.

>>> # subq는 Exists객체입니다.
+>>> subq = (
+...     select(func.count(address_table.c.id)).
+...     where(user_table.c.id == address_table.c.user_id).
+...     group_by(address_table.c.user_id).
+...     having(func.count(address_table.c.id) > 1)
+... ).exists()
+>>> print(subq)
+"""
+EXISTS (SELECT count(address.id) AS count_1 
+FROM address, user_account 
+WHERE user_account.id = address.user_id GROUP BY address.user_id 
+HAVING count(address.id) > :count_2)
+"""
+>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         select(user_table.c.name).where(subq)
+...     )
+...     print(result.all())
+
+[('sandy',)]
+

한편 EXISTS 구문은 부정으로 사용되지 않는 경우가 더 많습니다.

# 이메일 주소가 없는 유저네임을 선택하는 쿼리문입니다.
+# "~" 연산이 들어간 부분을 확인해보세요
+>>> subq = (
+...     select(address_table.c.id).
+...     where(user_table.c.id == address_table.c.user_id)
+... ).exists()
+>>> stmt = select(user_table.c.name).where(~subq)
+>>> print(stmt)
+"""
+SELECT user_account.id 
+FROM user_account 
+WHERE NOT (EXISTS (SELECT count(address.id) AS count_1 
+FROM address 
+WHERE user_account.id = address.user_id GROUP BY address.user_id 
+HAVING count(address.id) > :count_2))
+"""
+>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[('patrick',)]
+

# SQL 함수 다뤄보기

이 섹션 앞부분의 그룹함수 :GROUP BY, HAVING에서 처음 소개된 func 객체는 +새로운 Function 객체를 생성하기 위한 팩토리 역할을 합니다.
select()와 같은 구문을 사용 할때는 인자 값으로 func객체로 생성된 SQL함수를 받을 수 있습니다.

  • count() : 집계함수로 행의 개수를 출력하는데 사용됩니다.
    >>> # cnt는 <class 'sqlalchemy.sql.functions.count'>타입입니다.
    +>>> cnt = func.count() 
    +>>> print(select(cnt).select_from(user_table))
    +"""
    +SELECT count(*) AS count_1FROM user_account
    +"""
    +
  • lower() : 문자열 함수로 문자열을 소문자로 바꿔줍니다.
    >>> print(select(func.lower("A String With Much UPPERCASE")))
    +"""
    +SELECT lower(:lower_2) AS lower_1
    +"""
    +
  • now() : 현재 시간과 날짜를 반환해주는 함수입니다. +이 함수는 굉장히 흔하게 사용되는 함수이기에 SQLAlchemy는 서로 다른 백엔드에서 손쉽게 렌더링 할 수 있도록 도와줍니다.
    >>> stmt = select(func.now())
    +>>> with engine.connect() as conn:
    +...     result = conn.execute(stmt)
    +...     print(result.all())
    +
    +[(datetime.datetime(...),)]
    +

다양한 데이터베이스 백엔드에서는 서로 다른 이름의 SQL함수를 갖고 있습니다.
+따라서 func 는 가능한 자유롭게 어떤 이름이든 func의 네임스페이스에 접근 할 수 있도록 허용합니다. 그리고 그 이름을 자동으로 SQL 함수로 받아들여 렌더링 합니다.

>>> # crazy_function의 데이터 타입은 Function입니다.
+>>> crazy_function = func.some_crazy_function(user_table.c.fullname, 17)
+>>> print(select(crazy_function))
+"""
+SELECT some_crazy_function(user_account.name, :some_crazy_function_2) AS some_crazy_function_1
+FROM user_account
+"""
+

한편 SQLAlchemy에서는 SQL에서 일반적으로 자주 쓰이는 count, now, max , concat같은 SQL 함수를 백엔드별로 적절한 데이터 타입을 제공합니다.

>>> from sqlalchemy.dialects import postgresql
+>>> print(select(func.now()).compile(dialect=postgresql.dialect()))
+"""
+SELECT now() AS now_1
+"""
+
+>>> from sqlalchemy.dialects import oracle
+>>> print(select(func.now()).compile(dialect=oracle.dialect()))
+"""
+SELECT CURRENT_TIMESTAMP AS now_1 FROM DUAL
+"""
+

# Functions Have Return Types

원문의 Functions Have Return Types 부분은 제가 이해하지 못했습니다. +이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.


# Built-in Functions Have Pre-Configured Return Types

원문의 Built-in Functions Have Pre-Configured Return Types 부분은 제가 이해하지 못했습니다. +이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.


# 윈도우 함수

윈도우 함수는 GROUP BY와 비슷한 함수이고 행간의 관계를 쉽게 정의 하기 위해 만든 함수입니다.
+윈도우 함수에 대해 알고 싶으신 분들은 민지님 블로그 (opens new window)에 자세한 설명이 나와있으니 한 번 읽어보시고 아래의 내용들을 이어서 읽어주세요.

SQLAlchemy에서는, func 네임스페이스에 의해 생성된 모든 SQL 함수 중 하나로 +OVER 구문을 구현하는 FunctionElement.over() 메서드가 있습니다.

윈도우 함수 중 하나로 행의 개수를 세는 row_number() 함수가 있습니다.
+각 행을 사용자 이름대로 그룹을 나누고 그 안에서 이메일 주소에 번호를 매길 수 있습니다.

# FunctionElement.over.partition_by파라미터를 사용하여 
+# PARTITION BY 절이 OVER 절에 렌더링되도록 했습니다.
+>>> stmt = select(
+...     func.row_number().over(partition_by=user_table.c.name),
+...     user_table.c.name,
+...     address_table.c.email_address
+... ).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+[(1, 'sandy', 'sandy@sqlalchemy.org'), 
+ (2, 'sandy', 'sandy@squirrelpower.org'), 
+ (1, 'spongebob', 'spongebob@sqlalchemy.org')]
+

FunctionElement.over.order_by를 사용하여 ORDER BY 절을 사용할 수도 있습니다.

>>> stmt = select(
+...     func.count().over(order_by=user_table.c.name),
+...     user_table.c.name,
+...     address_table.c.email_address).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+[(2, 'sandy', 'sandy@sqlalchemy.org'), 
+ (2, 'sandy', 'sandy@squirrelpower.org'), 
+ (3, 'spongebob', 'spongebob@sqlalchemy.org')]
+

# WITHIN GROUP, FILTER등 특수한 지정자

WITHIN GORUP이라는 SQL 구문은 순서 집합 또는 가상 집합 그리고 집계함수와 함께 쓰입니다. +일반적인 순서 집합 함수는 percentile_cont() 그리고 rank()를 포함하고 있습니다. +SQLAlchemy에서는 rank, dense_rank, percentile_count, percentile_disc가 구현되어 있고 +각각은 FunctionElement.within_group()메서드를 갖고 있습니다.

>>> print(
+...     func.unnest(
+...         func.percentile_disc([0.25,0.5,0.75,1]).within_group(user_table.c.name)
+...     )
+... )
+"""
+unnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))
+"""
+

어떤 백엔드에서는 "FILTER"를 지원하는데 이는 FunctionElement.filter()메서드로 사용이 가능합니다.

>>> stmt = select(
+...     func.count(address_table.c.email_address).filter(user_table.c.name == 'sandy'),
+...     func.count(address_table.c.email_address).filter(user_table.c.name == 'spongebob')
+... ).select_from(user_table).join(address_table)
+>>> with engine.connect() as conn:  
+...     result = conn.execute(stmt)
+...     print(result.all())
+
+"""
+SELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,
+count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2
+FROM user_account JOIN address ON user_account.id = address.user_id
+"""
+
+('sandy', 'spongebob')
+[(2, 1)]
+

# Table-Valued Functions

원문의 Table-Valued Functions 부분은 제가 이해하지 못했습니다. +이에 대해 이해하신 분 있으시다면 이 부분에 기여 부탁드립니다. 감사합니다.


# 컬럼값 함수 또는 스칼라 컬럼(테이블값 함수)

Oracle과 PostgresSQL에서 지원하는 특별 문법 중 하나로 FROM절에 세팅되는 함수들이 있습니다.
+PostgreSQL에서는 json_array_elements(), json_object_keys(), json_each_text(), json_each()등의 함수가 그 예입니다.

SQLAlchemy는 이러한 함수를 컬럼 값이라고 하며 Function객체에 지정자로 FunctionElement.column_valued()로 적용하여 사용할 수 있습니다.

>>> from sqlalchemy import select, func
+>>> stmt = select(func.json_array_elements('["one", "two"]').column_valued("x"))
+>>> print(stmt)
+"""
+SELECT x
+FROM json_array_elements(:json_array_elements_1) AS x
+"""
+

컬럼값 함수는 오라클에서도 아래와 같이 커스텀 SQL 함수로 사용할 수 있습니다.

>>> from sqlalchemy.dialects import oracle
+>>> stmt = select(func.scalar_strings(5).column_valued("s"))
+>>> print(stmt.compile(dialect=oracle.dialect()))
+"""
+SELECT COLUMN_VALUE s
+FROM TABLE (scalar_strings(:scalar_strings_1)) s
+"""
+
+ + + diff --git "a/tutorial/5.2. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\202\275\354\236\205\355\225\230\352\270\260.html" "b/tutorial/5.2. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\202\275\354\236\205\355\225\230\352\270\260.html" new file mode 100644 index 0000000..9bb5b92 --- /dev/null +++ "b/tutorial/5.2. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\202\275\354\236\205\355\225\230\352\270\260.html" @@ -0,0 +1,106 @@ + + + + + + Core 방식으로 행 삽입하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# Core 방식으로 행 삽입하기

이번 챕터에서는 SQLAlchemy Core 방식으로 데이터를 INSERT 하는 방법을 배웁니다.


# insert() 를 통한 SQL 표현식 구성

먼저 다음처럼 INSERT 구문을 만들 수 있습니다.

>>> from sqlalchemy import insert
+
+#  stmt는 Insert 객체 인스턴스입니다.
+>>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")
+>>> print(stmt)
+'INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)'
+

여기서 user_table은 우리가 이전 챕터에서 만든 Table 객체입니다. 우리는 아래처럼 만들었었습니다.

from sqlalchemy import MetaData
+from sqlalchemy import Table, Column, Integer, String
+
+metadata = MetaData()
+user_table = Table(
+    'user_account',
+    metadata,
+    Column('id', Integer, primary_key=True),
+    Column('name', String(30)),
+    Column('fullname', String),
+)
+

stmt 를 보면 아직 매개변수가 매핑되지는 않았습니다.
+이는 다음처럼 complie() 한 후에 확인할 수 있습니다.

>>> compiled = stmt.compile()
+>>> print(compiled.params)
+{'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}
+

# 명령문 실행

이제 위에서 만든 INSERT 구문을 Core 방식으로 실행해봅시다.

>>> with engine.connect() as conn:
+...     result = conn.execute(stmt)
+...     conn.commit()
+
+# 위 코드는  결과적으로 아래 쿼리를 실행합니다.
+BEGIN (implicit)
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('spongebob', 'Spongebob Squarepants')
+COMMIT
+

conn.execute(stmt) 의 반환 값을 받은 result 에는 어떤 정보가 있을까요?
resultCursorResult (opens new window) 객체입니다.
+여기에는 실행 결과물에 대한 여러 정보를 담고있는데, 특히 데이터 행을 담고있는 Row (opens new window) 객체를 들고있습니다.

우리는 방금 데이터를 삽입했고, 이에 대한 결과물로 다음처럼 삽입된 데이터의 기본 키 값을 확인할 수 있습니다.

>>> result.inserted_primary_key  # 이 역시 Row 객체입니다.
+(1, )  # 기본 키가 여러 열로 구성될 수 있으므로 튜플로 표현됩니다.
+

# Connection.execute() 에 INSERT 매개변수 전달하기

위에서는 다음처럼 insertvalues 까지 함께 포함하여 구문울 만들었습니다.

>>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")
+

하지만 이 방법 외에도 다음처럼 Connection.execute() 메서드에 매개변수를 전달하여 INSERT 구문을 실행할 수 있습니다.
+공식문서에는 이게 좀 더 일반적인 방법이라고 말합니다.

>>> with engine.connect() as conn:
+...     result = conn.execute(
+...         insert(user_table),
+...         [
+...             {"name": "sandy", "fullname": "Sandy Cheeks"},
+...             {"name": "patrick", "fullname": "Patrick Star"}
+...         ]
+...     )
+...     conn.commit()
+

공식문서에는 하위 쿼리까지 포함하여 실행시키는 법을 별도의 블락에서 설명하고 있는데, 튜토리얼 내용으로는 다소 적합하지 않다고 판단하여 이 글에는 포함하지 않았습니다. +이 내용이 궁금하신 분들은 원문 링크 (opens new window)를 참고하세요.


# Insert.from_select()

다음처럼 SELECT 하여 받은 행들을 INSERT 하기 위한 쿼리가 필요한 경우가 있습니다.

이런 사례는 예를 들면 다음 코드처럼 작성할 수 있습니다.

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
+>>> insert_stmt = insert(address_table).from_select(
+...     ["user_id", "email_address"], select_stmt
+... )
+>>> print(insert_stmt)
+"""
+INSERT INTO address (user_id, email_address)
+SELECT user_account.id, user_account.name || :name_1 AS anon_1
+FROM user_account
+"""
+

# Insert.returning()

데이터베이스에서 쿼리 처리 후에 처리된 행의 값을 반환받아야 하는 경우가 있습니다. 이를 RETURNING 문법이라 합니다.
+이에 대한 소개 글은 이 블로그 글 (opens new window)을 읽어보시면 좋을거 같습니다.

SQLAlchemy Core에서는 이런 RETURNING 문법을 다음처럼 작성할 수 있습니다.

>>> insert_stmt = insert(address_table).returning(address_table.c.id, address_table.c.email_address)
+>>> print(insert_stmt)
+"""
+INSERT INTO address (id, user_id, email_address)
+VALUES (:id, :user_id, :email_address)
+RETURNING address.id, address.email_address
+"""
+
+ + + diff --git "a/tutorial/5.3. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\210\230\354\240\225 \353\260\217 \354\202\255\354\240\234\355\225\230\352\270\260.html" "b/tutorial/5.3. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\210\230\354\240\225 \353\260\217 \354\202\255\354\240\234\355\225\230\352\270\260.html" new file mode 100644 index 0000000..99704ae --- /dev/null +++ "b/tutorial/5.3. Core \353\260\251\354\213\235\354\234\274\353\241\234 \355\226\211 \354\210\230\354\240\225 \353\260\217 \354\202\255\354\240\234\355\225\230\352\270\260.html" @@ -0,0 +1,150 @@ + + + + + + Core 방식으로 행 수정 및 삭제하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# Core 방식으로 행 수정 및 삭제하기

이번 챕터에서는 Core 방식으로 기존 행을 수정하고 삭제하는 데 사용되는 Update 및 Delete 구문에 대해 설명합니다.


# update() 를 통한 SQL 표현식 구성

다음처럼 UPDATE 구문을 작성할 수 있습니다.

>>> from sqlalchemy import update
+>>> stmt = (
+...     update(user_table).where(user_table.c.name == 'patrick').
+...     values(fullname='Patrick the Star')
+... )
+>>> print(stmt)
+'UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1'
+
>>> stmt = (
+...     update(user_table).
+...     values(fullname="Username: " + user_table.c.name)
+... )
+>>> print(stmt)
+'UPDATE user_account SET fullname=(:name_1 || user_account.name)'
+

원문에는 bindparam() 에 대한 내용이 나오는데, 사용 사례를 잘 본 적이 없어서 이 글에서는 생략합니다. 궁금하신 분은 원문 내용 (opens new window)을 참고하세요.


# Correlated 업데이트

다음처럼 Correlated Subquery (opens new window)를 사용하여 다른 테이블의 행을 사용할 수 있습니다.

>>> scalar_subq = (
+...   select(address_table.c.email_address).
+...   where(address_table.c.user_id == user_table.c.id).
+...   order_by(address_table.c.id).
+...   limit(1).
+...   scalar_subquery()
+... )
+>>> update_stmt = update(user_table).values(fullname=scalar_subq)
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=(SELECT address.email_address
+FROM address
+WHERE address.user_id = user_account.id ORDER BY address.id
+LIMIT :param_1)
+"""
+

# 다른 테이블과 연관된 조건으로 업데이트

테이블을 업데이트할 때, 다른 테이블의 정보와 연관하여 조건을 설정해야할 때가 있습니다.
+이 경우, 예를들면 다음처럼 사용할 수 있습니다.

>>> update_stmt = (
+...    update(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com').
+...    values(fullname='Pat')
+...  )
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=:fullname FROM address
+WHERE user_account.id = address.user_id AND address.email_address = :email_address_1
+"""
+

# 여러 테이블 동시에 업데이트

다음처럼 여러 테이블에서 조건에 해당하는 특정 값들을 동시에 업데이트할 수 있습니다.

>>> update_stmt = (
+...    update(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com').
+...    values(
+...        {
+...            user_table.c.fullname: "Pat",
+...            address_table.c.email_address: "pat@aol.com"
+...        }
+...    )
+...  )
+>>> from sqlalchemy.dialects import mysql
+>>> print(update_stmt.compile(dialect=mysql.dialect()))
+"""
+UPDATE user_account, address
+SET address.email_address=%s, user_account.fullname=%s
+WHERE user_account.id = address.user_id AND address.email_address = %s
+"""
+

원문의 Parameter Ordered Updates 부분은 제가 이해하지 못하여 정리하지 않았습니다.
+잘 아시는 분이 있으면 이 문서에 기여해주시면 감사하겠습니다.


# delete() 를 통한 SQL 표현식 구성

다음처럼 DELETE 구문을 작성할 수 있습니다.

>>> from sqlalchemy import delete
+>>> stmt = delete(user_table).where(user_table.c.name == 'patrick')
+>>> print(stmt)
+"""
+DELETE FROM user_account WHERE user_account.name = :name_1
+"""
+

# 다른 테이블과 조인하여 삭제

다른 테이블과 조인한 뒤, 특정 조건에 맞는 데이터만 삭제해야 하는 경우가 있습니다. (이해가 안간다면 이 글 (opens new window)을 참고해보세요.) +이 경우, 예를들면 다음처럼 사용할 수 있습니다.

>>> delete_stmt = (
+...    delete(user_table).
+...    where(user_table.c.id == address_table.c.user_id).
+...    where(address_table.c.email_address == 'patrick@aol.com')
+...  )
+>>> from sqlalchemy.dialects import mysql
+>>> print(delete_stmt.compile(dialect=mysql.dialect()))
+"""
+DELETE FROM user_account USING user_account, address
+WHERE user_account.id = address.user_id AND address.email_address = %s
+"""
+

# UPDATE, DELETE에서 영향을 받는 행 수 얻기

다음처럼 Result.rowcount 속성 (opens new window)을 통해 쿼리가 처리한 행 수를 가져올 수 있습니다.

>>> with engine.begin() as conn:
+...     result = conn.execute(
+...         update(user_table).
+...         values(fullname="Patrick McStar").
+...         where(user_table.c.name == 'patrick')
+...     )
+...     print(result.rowcount)  # Result 객체의 rowcount 속성을 사용합니다.
+
+1  # 쿼리가 처리한 행 수 (조건절에 걸리는 행 수와 같습니다.)
+

# UPDATE, DELETE와 함께 RETURNING 사용하기

다음처럼 RETURNING 문법을 사용할 수 있습니다. (RETURNING 문법에 대해서는 이 글 (opens new window)을 참고해보세요.)

>>> update_stmt = (
+...     update(user_table).where(user_table.c.name == 'patrick').
+...     values(fullname='Patrick the Star').
+...     returning(user_table.c.id, user_table.c.name)
+... )
+>>> print(update_stmt)
+"""
+UPDATE user_account SET fullname=:fullname
+WHERE user_account.name = :name_1
+RETURNING user_account.id, user_account.name
+"""
+
>>> delete_stmt = (
+...     delete(user_table).where(user_table.c.name == 'patrick').
+...     returning(user_table.c.id, user_table.c.name)
+... )
+>>> print(delete_stmt)
+"""
+DELETE FROM user_account
+WHERE user_account.name = :name_1
+RETURNING user_account.id, user_account.name
+"""
+
+ + + diff --git "a/tutorial/6. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \353\215\260\354\235\264\355\204\260 \354\241\260\354\236\221\355\225\230\352\270\260.html" "b/tutorial/6. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \353\215\260\354\235\264\355\204\260 \354\241\260\354\236\221\355\225\230\352\270\260.html" new file mode 100644 index 0000000..b31e141 --- /dev/null +++ "b/tutorial/6. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \353\215\260\354\235\264\355\204\260 \354\241\260\354\236\221\355\225\230\352\270\260.html" @@ -0,0 +1,207 @@ + + + + + + ORM 방식으로 데이터 조작하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# ORM 방식으로 데이터 조작하기

이전 챕터까지 CORE 관점에서 쿼리를 활용하는 방식에 초점을 맞췄습니다. 이번 챕터에서는 ORM 방식에서 쓰이는 Session의 구성 요소와 수명 주기, 상호 작용하는 방법을 설명합니다.


# ORM으로 행 삽입하기

Session 객체는 ORM을 사용할 때 Insert 객체들을 만들고 트랜잭션에서 이 객체들을 내보내는 역할을 합니다. +Session은 이러한 과정들을 수행하기 위해 객체 항목을 추가합니다. +그 후 flush라는 프로세스를 통해 새로운 항목들을 데이터베이스에 기록합니다.

# 행을 나타내는 객체의 인스턴스

이전 과정에서 우리는 Python Dict를 사용하여 INSERT를 실행하였습니다.

ORM에서는 테이블 메타데이터 정의에서 정의한 사용자 정의 Python 객체를 직접 사용합니다.

>>> squidward = User(name="squidward", fullname="Squidward Tentacles")
+>>> krabs = User(name="ehkrabs", fullname="Eugene H. Krabs")
+

INSERT 될 잠재적인 데이터베이스 행을 나타내는 두 개의 User 객체를 만듭니다. +ORM 매핑에 의해 자동으로 생성된 __init__() 생성자 덕에 생성자의 열 이름을 키로 사용하여 각 객체를 생성할 수 있습니다.

>>> squidward
+User(id=None, name='squidward', fullname='Squidward Tentacles')
+

Core의 Insert와 유사하게, 기본 키를 포함하지 않아도 ORM이 이를 통합시켜 줍니다. +idNone 값은 속성에 아직 값이 없음을 나타내기 위해 SQLAlchemy에서 제공합니다.

현재 위의 두 객체(squiwardkrabs)는 transient 상태라고 불리게 됩니다. +transient 상태란, 어떤 데이터베이스와 연결되지 않고, INSERT문을 생성할 수 있는 Session객체와도 아직 연결되지 않은 상태를 의미합니다.

# Session에 객체 추가하기

>>> session = Session(engine) # 반드시 사용 후 close 해야 합니다.
+>>> session.add(squidward) # Session.add() 매소드를 통해서 객체를 Session에 추가해줍니다.
+>>> session.add(krabs)
+

객체가 Session.add()를 통해서 Session에 추가하게 되면, pending 상태가 되었다고 부릅니다. +pending 상태는 아직 데이터베이스에 추가되지 않은 상태입니다.

>>> session.new # session.new를 통해서 pending 상태에 있는 객체들을 확인할 수 있습니다.
+IdentitySet([User(id=None, name='squidward', fullname='Squidward Tentacles'), User(id=None, name='ehkrabs', fullname='Eugene H. Krabs')])
+
  • IdentitySet은 모든 경우에 객체 ID를 hash하는 Python set입니다.
  • 즉, Python 내장 함수 중 hash()가 아닌, id() 메소드를 사용하고 있습니다.

# Flushing

Session 객체는 unit of work 패턴 (opens new window)을 사용합니다. 이는 변경 사항을 누적하지만, 필요할 때까지는 실제로 데이터베이스와 통신을 하지 않음을 의미합니다. +이런 동작 방식을 통해서 위에서 언급한 pending 상태의 객체들이 더 효율적인 SQL DML로 사용됩니다. +현재의 변경된 사항들을 실제로 Database에 SQL을 통해 내보내는 작업을 flush 이라고 합니다.

>>> session.flush()
+"""
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('squidward', 'Squidward Tentacles')
+INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('ehkrabs', 'Eugene H. Krabs')
+"""
+

이제 트랜잭션은 Session.commit(), Session.rollback(), Session.close() 중 하나가 호출될 때 까지 열린 상태로 유지됩니다.

Session.flush()를 직접 사용하여, 현재 pending 상태에 있는 내용을 직접 밀어넣을 수 있지만, Session은 autoflush라는 동작을 특징으로 하므로 일반적으로는 필요하지 않습니다. Session.commit()이 호출 될 때 마다 변경 사항을 flush 합니다.

# 자동 생성된 기본 키 속성

행이 삽입되게 되면, 우리가 생성한 Python 객체는 persistent 라는 상태가 됩니다. +persistent 상태는 로드된 Session 객체와 연결됩니다.

INSERT 실행 시, ORM이 각각의 새 객체에 대한 기본 키 식별자를 검색하는 효과를 가져옵니다. +이전에 소개한것과 동일한 CursorResult.inserted_primary_key 접근자를 사용합니다.

>>> squidward.id
+4
+>>> krabs.id
+5
+

ORM이 flush 될 때, executemany 대신, 두 개의 다른 INSERT 문을 사용하는 이유가 바로 이 CursorResult.inserted_primary_key 때문입니다.

  • SQLite의 경우 한 번에 한 열을 INSERT 해야 자동 증가 기능을 사용할 수 있습니다.(PostgreSQL의 IDENTITY나 SERIAL 기능등 다른 다양한 데이터베이스들의 경우들도 이처럼 동작합니다.)
  • psycopg2와 같이 한번에 많은 데이터에 대한 기본 키 정보를 제공 받을 수 있는 데이터베이스가 연결되어 있다면, ORM은 이를 최적화하여 많은 열을 한번에 INSERT 하도록 합니다.

# Identity Map

Identity Map(ID Map)은 현재 메모리에 로드된 모든 객체를 기본 키 ID에 연결하는 메모리 내 저장소입니다. +Session.get()을 통해서 객체 중 하나를 검색할 수 있습니다. +이 메소드는 객체가 메모리에 있으면, ID Map에서, 그렇지 않으면 SELECT문을 통해서 객체를 검색합니다.

>>> some_squidward = session.get(User, 4)
+>>> some_squidward
+User(id=4, name='squidward', fullname='Squidward Tentacles')
+

중요한 점은, ID Map은 Python 객체 중에서도 고유한 객체를 유지하고 있다는 점입니다.

>>> some_squidward is squidward 
+True
+

ID map은 동기화되지 않은 상태에서, 트랜잭션 내에서 복잡한 개체 집합을 조작할 수 있도록 하는 중요한 기능입니다.

# Committing

현재까지의 변경사항을 트랜잭션에 commit 합니다.

>>> session.commit()
+COMMIT
+

# ORM 객체 UPDATE하기

ORM을 통해 UPDATE 하는 방법에는 2가지 방법이 있습니다.

  1. Session에서 사용하는 unit of work 패턴 방식이 있습니다. 변경사항이 있는 기본 키 별로 UPDATE 작업이 순서대로 내보내지게 됩니다.
  2. "ORM 사용 업데이트"라고 하며 명시적으로 Session과 함께 Update 구성을 사용할 수도 있습니다.

# 변경사항을 자동으로 업데이트하기

>>> sandy = session.execute(select(User).filter_by(name="sandy")).scalar_one()
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('sandy',)
+"""
+

이 'Sandy' 유저 객체는 데이터베이스에서 행, 더 구체적으로는 트랙잭션 측면에서 기본 키가 2인 행에 대한 proxy 역할을 합니다.

>>> sandy
+User(id=2, name='sandy', fullname='Sandy Cheeks')
+>>> sandy.fullname = "Sandy Squirrel" # 객체의 속성을 변화시키면, Session은 이 변화를 기록합니다.
+>>> sandy in session.dirty # 이렇게 변한 객체는 dirty 라고 불리우며 session.dirty에서 확인 할 수 있습니다.
+True
+

Session이 flush를 실행하게 되면, 데이터베이스에서 UPDATE가 실행되어 데이터베이스에 실제로 값을 갱신합니다. SELECT 문을 추가로 실행하게 되면, 자동으로 flush가 실행되어 sandy의 바뀐 이름 값을 SELECT를 통해서 바로 얻을 수 있습니다.

>>> sandy_fullname = session.execute(
+...     select(User.fullname).where(User.id == 2)
+... ).scalar_one()
+"""
+UPDATE user_account SET fullname=? WHERE user_account.id = ?
+[...] ('Sandy Squirrel', 2)
+SELECT user_account.fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (2,)
+"""
+>>> print(sandy_fullname)
+Sandy Squirrel
+# flush를 통해 sandy의 변화가 실제로 데이터베이스에 반영되어, dirty 속성을 잃게 됩니다.
+>>> sandy in session.dirty 
+False
+

# ORM 사용 업데이트

ORM을 통해 UPDATE 하는 마지막 방법으로 ORM 사용 업데이트를 명시적으로 사용하는 방법이 있습니다. 이를 사용하면 한 번에 많은 행에 영향을 줄 수 있는 일반 SQL UPDATE 문을 사용할 수 있습니다.

>>> session.execute(
+...     update(User).
+...     where(User.name == "sandy").
+...     values(fullname="Sandy Squirrel Extraordinaire")
+... )
+"""
+UPDATE user_account SET fullname=? WHERE user_account.name = ?
+[...] ('Sandy Squirrel Extraordinaire', 'sandy')
+"""
+<sqlalchemy.engine.cursor.CursorResult object ...>
+

현재 Session에서 주어진 조건과 일치하는 객체가 있다면, 이 객체에도 해당하는 update가 반영되게 됩니다.

>>> sandy.fullname
+'Sandy Squirrel Extraordinaire'
+

# ORM 객체를 삭제하기

Session.delete() 메서드를 사용하여 개별 ORM 객체를 삭제 대상으로 표시할 수 있습니다. delete가 수행되면, 해당 Session에 존재하는 객체들은 expired 상태가 되게 됩니다.

>>> patrick = session.get(User, 3)
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (3,)
+"""
+>>> session.delete(patrick) # patrik을 삭제 할 것이라고 명시
+>>> session.execute(select(User).where(User.name == "patrick")).first() # 이 시점에서 flush 실행
+"""
+SELECT address.id AS address_id, address.email_address AS address_email_address,
+address.user_id AS address_user_id
+FROM address
+WHERE ? = address.user_id
+[...] (3,)
+DELETE FROM user_account WHERE user_account.id = ?
+[...] (3,)
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('patrick',)
+"""
+>>> squidward in session # Session에서 만료되면, 해당 객체는 session에서 삭제됩니다.
+False
+

위의 UPDATE에서 사용된 'Sandy'와 마찬가지로, 해당 작업들은 진행중인 트랜잭션에서만 이루어진 일이며 commit 하지 않는 이상, 언제든 취소할 수 있습니다.

# ORM 사용 삭제하기

UPDATE와 마찬가지로 ORM 사용 삭제하기도 있습니다.

# 예시를 위한 작업일 뿐, 실제로 delete에서 필요한 작업은 아닙니다.
+>>> squidward = session.get(User, 4)
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (4,)
+"""
+
+>>> session.execute(delete(User).where(User.name == "squidward"))
+"""
+DELETE FROM user_account WHERE user_account.name = ?
+[...] ('squidward',)
+<sqlalchemy.engine.cursor.CursorResult object at 0x...>
+"""
+

# Rolling Back

Session에는 현재의 작업들을 롤백하는 Session.rollback() 메소드가 존재합니다. 이 메소드는 위에서 사용된 sandy와 같은 Python 객체에도 영향을 미칩니다. +Session.rollback()을 호출하면 트랜잭션을 롤백할 뿐만 아니라 현재 이 Session과 연결된 모든 객체를 expired 상태로 바꿉니다. 이러한 상태 변경은 다음에 객체에 접근 할 때 스스로 새로 고침을 하는 효과가 있고 이러한 프로세스를 지연 로딩 이라고 합니다.

>>> session.rollback()
+ROLLBACK
+

expired 상태의 객체인 sandy 를 자세히 보면, 특별한 SQLAlchemy 관련 상태 객체를 제외하고 다른 정보가 남아 있지 않음을 볼 수 있습니다.

>>> sandy.__dict__
+{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>}
+>>> sandy.fullname # session이 만료되었으므로, 해당 객체 속성에 접근 시, 트랜잭션이 새로 일어납니다.
+"""
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (2,)
+"""
+'Sandy Cheeks'
+>>> sandy.__dict__  #이제 데이터베이스 행이 sandy 객체에도 채워진 것을 볼 수 있습니다.
+{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>,
+ 'id': 2, 'name': 'sandy', 'fullname': 'Sandy Cheeks'}
+

삭제된 객체에 대해서도, Session에 다시 복원되었으며 데이터베이스에도 다시 나타나는 걸 볼 수 있습니다.

>>> patrick in session
+True
+>>> session.execute(select(User).where(User.name == 'patrick')).scalar_one() is patrick
+"""
+SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.name = ?
+[...] ('patrick',)
+"""
+True
+

# Session 종료하기

우리는 컨텍스트 구문 외부에서 Session을 다뤘는데, 이런 경우 다음처럼 명시적으로 Session을 닫아주는 것이 좋습니다.

>>> session.close()
+ROLLBACK
+

마찬가지로 컨텍스트 구문을 통해 생성한 Session을 컨텍스트 구문 내에서 닫으면 다음 작업들이 수행됩니다.

  • 진행 중인 모든 트랜잭션을 취소(예: 롤백)하여 연결 풀에 대한 모든 연결 리소스를 해제합니다. +
    • 즉, Session을 사용하여 일부 읽기 전용 작업을 수행한 다음, 닫을 때 트랜잭션이 롤백되었는지 확인하기 위해 Session.rollback()을 명시적으로 호출할 필요가 없습니다. 연결 풀이 이를 처리합니다.
  • Session에서 모든 개체를 삭제합니다. +
    • 이것은 sandy, patrick 및 squidward와 같이 이 Session에 대해 로드한 모든 Python 개체가 이제 detached 상태에 있음을 의미합니다. 예를 들어 expired 상태에 있던 객체는 Session.commit() 호출로 인해 현재 행의 상태를 포함하지 않고 새로 고칠 데이터베이스 트랜잭션과 더 이상 연관되지 않습니다.
    • >>> squidward.name
      +Traceback (most recent call last):
      +...
      +sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x...> is not bound to a Session; attribute refresh operation cannot proceed
      +
    • detached된 객체는 Session.add() 메서드를 사용하여 동일한 객체 또는 새 Session과 다시 연결될 수 있습니다. 그러면 특정 데이터베이스 행과의 관계가 다시 설정됩니다.
    • >>> session.add(squidward) # session에 다시 연결
      +>>> squidward.name # 트랜잭션을 통해 정보를 다시 불러옵니다.
      +"""
      +SELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname
      +FROM user_account
      +WHERE user_account.id = ?
      +[...] (4,)
      +"""
      +'squidward'
      +

detached 상태의 개체는 되도록이면 사용을 지양해야 합니다. Session이 닫히면 이전에 연결된 모든 개체에 대한 참조도 정리합니다. 일반적으로 detached된 객체가 필요한 경우는 웹 어플리케이션에서 방금 커밋된 개체를 뷰에서 렌더링되기 전에 Session이 닫힌 경우가 있습니다. 이 경우 Session.expire_on_commit 플래그를 False로 설정합니다.

+ + + diff --git "a/tutorial/7. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \352\264\200\353\240\250 \352\260\234\354\262\264 \354\236\221\354\227\205\355\225\230\352\270\260.html" "b/tutorial/7. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \352\264\200\353\240\250 \352\260\234\354\262\264 \354\236\221\354\227\205\355\225\230\352\270\260.html" new file mode 100644 index 0000000..ae3ee04 --- /dev/null +++ "b/tutorial/7. ORM \353\260\251\354\213\235\354\234\274\353\241\234 \352\264\200\353\240\250 \352\260\234\354\262\264 \354\236\221\354\227\205\355\225\230\352\270\260.html" @@ -0,0 +1,373 @@ + + + + + + ORM으로 관련 개체 작업하기 | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# ORM으로 관련 개체 작업하기


이번 챕터에서는 다른 객체를 참조하는 매핑된 객체와 상호작용하는 방식인 또 하나의 필수적인 ORM 개념을 다룰 것입니다.
relationship()은 매핑된 두 객체 간의 관계를 정의하며, 자기 참조관계라고도 합니다.
+기본적인 구조를 위해 Column 매핑 및 기타 지시문을 생략하고 짧은 형식으로 relationship()을 설명드리겠습니다.


from sqlalchemy.orm import relationship
+
+
+class User(Base):
+    __tablename__ = 'user_account'
+
+    # ... Column mappings
+
+    addresses = relationship("Address", back_populates="user")
+
+
+class Address(Base):
+    __tablename__ = 'address'
+
+    # ... Column mappings
+
+    user = relationship("User", back_populates="addresses")
+

위 구조를 보면 User 객체에는 addresses 변수, Address 객체에는 user 라는 변수가 있습니다.
+공통적으로 relationship 객체로 생성되어져 있는 것을 볼 수 있습니다. +이는 실제 데이터베이스에 컬럼으로 존재하는 변수는 아니지만 코드 상에서 쉽게 접근할 수 있도록 하기 위해 설정 되었습니다.
+즉, User 객체에서 Address 객체로 쉽게 찾아갈 수 있게 해줍니다.

또한 relationship 선언시 파라미터로 back_populates 항목은 반대의 상황 즉, +Address 객체에서 User 객체를 찾아 갈 수 있게 해줍니다.

관계형으로 보았을 경우 1 : N 관계를 자연스럽게 N : 1 관계로 해주는 설정입니다.

다음 섹션에서 relationship() 객체의 인스턴스가 어떤 역할을 하는지, 동작하는지 보겠습니다.


# 관계된 객체 사용하기


새로운 User 객체를 만들면 .addresses 컬렉션이 나타나는데 List 객체임을 알 수 있습니다.

>>> u1 = User(name='pkrabs', fullname='Pearl Krabs')    
+>>> u1.addresses
+[]
+

list.append()를 사용하여 Address 객체를 추가할 수 있습니다.

>>> a1 = Address(email_address="pear1.krabs@gmail.com")
+>>> u1.addresses.append(a1)
+
+# u1.addresses 컬렉션에 새로운 Address 객체가 포함되었습니다.
+>>> u1.addresses
+[Address(id=None, email_address='pearl.krabs@gmail.com')]
+

Address 객체를 인스턴스 User.addresses 컬렉션과 연관시켰다면 변수 u1 에는 또 다른 동작이 발생하는데,
User.addressesAddress.user 관계가 동기화 되어

  • User 객체에서 Address 이동할 수 있을 뿐만 아니라
  • Address 객체에서 다시 User 객체로 이동할 수도 있습니다.
>>> a1.user
+User(id=None, name='pkrabs', fullname='Pearl Krabs')
+

두개의 relationshiop() 객체 간의 relationship.back_populates 을 사용한 동기화 결과입니다.

매개변수 relationshiop() 는 보완적으로 할당/목록 변형이 발생할때 다른 변수로 지정할 수 있습니다. +다른 Address 객체를 생성하고 해당 Address.user 속성에 할당하면 해당 객체 Address에 대한 User.addresses 컬렉션의 일부가 되는것도 확인 할 수 있습니다.

>>> a2 = Address(email_address="pearl@aol.com", user=u1)
+>>> u1.addresses
+[Address(id=None, email_address='pearl.krabs@gmail.com'), Address(id=None, email_address='pearl@aol.com')]
+

우리는 실제로 객체(Address)에 선언된 속성처럼 user의 키워드 인수로 u1 변수를 사용했습니다.
+다음 사실 이후에 속성을 할당하는 것과 같습니다.

# equivalent effect as a2 = Address(user=u1)
+>>> a2.user = u1
+

# Session에 객체 캐스케이딩


이제 메모리의 양방향 구조와 연결된 두 개의 User, Address 객체가 있지만 이전에 ORM으로 행 삽입하기 에서 언급했듯이 이러한 객체는 객체와 연결될 때까지 일시적인 Session 상태에 있습니다.

우리는 Session.add() 를 사용하고, User 객체에 메서드를 적용할 때 관련 Address 객체도 추가된다는 점을 확인해 볼 필요가 있습니다.

>>> session.add(u1)
+>>> u1 in session
+True
+>>> a1 in session
+True
+>>> a2 in session 
+True
+

세 개의 객체는 이제 보류 상태에 있으며, 이는 INSERT 작업이 진행되지 않았음을 의미합니다.
+세 객체는 모두 기본 키가 할당되지 않았으며, 또한 a1 및 a2 객체에는 열(user_id)을 참조 속성이 있습니다.
+이는 객체가 아직 실제 데이터베이스 연결되지 않았기 때문입니다.

>>> print(u1.id)
+None
+>>> print(a1.user_id)
+None
+

데이터베이스에 저장해봅시다.

>>> session.commit()
+

구현한 코드를 SQL 쿼리로 동작을 해본다면 이와 같습니다.

INSERT INTO user_account (name, fullname) VALUES (?, ?)
+[...] ('pkrabs', 'Pearl Krabs')
+INSERT INTO address (email_address, user_id) VALUES (?, ?)
+[...] ('pearl.krabs@gmail.com', 6)
+INSERT INTO address (email_address, user_id) VALUES (?, ?)
+[...] ('pearl@aol.com', 6)
+COMMIT
+

session을 사용하여 SQL의 INSERT, UPDATE, DELETE 문을 자동화할 수 있습니다. +마지막으로 Session.commit()을 실행하여 모든 단계를 올바른 순서로 호출되며 user_accountaddress.user_id 기본키가 적용됩니다.


# 관계 로드


Session.commit() 을 호출한 이후에는 u1 객체에 생성된 기본 키를 볼 수 있게됩니다.

>>> u1.id
+6
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

BEGIN (implicit)
+SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
+user_account.fullname AS user_account_fullname
+FROM user_account
+WHERE user_account.id = ?
+[...] (6,)
+

다음처럼 u1.addresses 에 연결된 객체들에도 id가 들어와있는 것을 볼 수 있습니다. +해당 객체를 검색하기 위해 우리는 lazy load 방식으로 볼 수 있습니다.

lazy loading : 누군가 해당 정보에 접근하고자 할때 그때 SELECT문을 날려서 정보를 충당하는 방식. 즉, 그때그때 필요한 정보만 가져오는 것입니다.

>>> u1.addresses
+[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id AS address_id, address.email_address AS address_email_address,
+address.user_id AS address_user_id
+FROM address
+WHERE ? = address.user_id
+[...] (6,)
+

SQLAlchemy ORM의 기본 컬렉션 및 관련 특성은 lazy loading 입니다. 즉, 한번 relationship 된 컬렉션은 데이터가 메모리에 존재하는 한 계속 접근을 사용할 수 있습니다.

>>> u1.addresses
+[Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]
+

lazy loading은 최적화를 위한 명시적인 단계를 수행하지 않으면 비용이 많이 들 수 있지만, 적어도 lazy loading은 중복 작업을 수행하지 않도록 최적화되어 있습니다.

u1.addresses의 컬렉션에 a1a2 객체들 또한 볼 수 있습니다.

>>> a1
+Address(id=4, email_address='pearl.krabs@gmail.com')
+>>> a2
+Address(id=5, email_address='pearl@aol.com')
+

relationship 개념에 대한 추가 소개는 이 섹션의 후반부에 더 설명드리겠습니다.


# 쿼리에서 relationship 사용하기


이 섹션에서는 relationship() 이 SQL 쿼리 구성을 자동화하는데 도움이 되는 여러 가지 방법을 소개합니다.


# relationship()을 사용하여 조인하기

FROM절과 JOIN명시하기WHERE절 섹션에서는 Select.join()Select.join_from() 메서드를 사용하여 SQL JOIN을 구성하였습니다.
+테이블간에 조인하는 방법을 설명하기 위해 이러한 메서드는 두 테이블을 연결하는 ForeignKeyConstraint 객체가 있는지 여부에 따라 ON 절을 유추하거나 특정 ON 절을 나타내는 SQL Expression 구문을 제공 할 수 있습니다.

relationship() 객체를 사용하여 join의 ON 절을 설정할 수 있습니다. +relationship() 에 해당하는 객체는 Select.join()단일 인수로 전달될 수 있으며, +right join과 ON 절을 동시에 나타내는 역할을 합니다.

>>> print(
+...     select(Address.email_address).
+...     select_from(User).
+...     join(User.addresses)
+... )
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+

매핑된 relationship()있는 경우 Select.join() 또는 Select.join_from() 지정하지 않을 경우 ON 절은 사용되지 않습니다.
+즉, userAddress 객체의 relationship() 객체가 아니라 매핑된 두 테이블 객체 간의 ForeignKeyConstraint로 인해 작동합니다.

>>> print(
+...    select(Address.email_address).
+...    join_from(User, Address)
+... )
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.email_address
+FROM user_account JOIN address ON user_account.id = address.user_id
+

# 별칭(aliased)을 사용하여 조인하기

relationship()을 사용하여 SQL JOIN을 구성하는 경우 [PropComparator.of_type()] 사용하여 조인 대상이 aliased()이 되는 사용 사례가 적합합니다. 그러나 relationship()를 사용하여 [ORM Entity Aliases]에 설명된 것과 동일한 조인을 구성합니다.

>>> from sqlalchemy.orm import aliased
+>>> address_alias_1 = aliased(Address)
+>>> address_alias_2 = aliased(Address)
+>>> print(
+...     select(User).
+...     join_from(User, address_alias_1).
+...     where(address_alias_1.email_address == 'patrick@aol.com').
+...     join_from(User, address_alias_2).
+...     where(address_alias_2.email_address == 'patrick@gmail.com')
+... )
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+JOIN address AS address_1 ON user_account.id = address_1.user_id
+JOIN address AS address_2 ON user_account.id = address_2.user_id
+WHERE address_1.email_address = :email_address_1
+AND address_2.email_address = :email_address_2
+

relationship()을 사용하여 aliased()에서 조인을 직접 사용할 수 있습니다.

>>> user_alias_1 = aliased(User)
+>>> print(
+...     select(user_alias_1.name).
+...     join(user_alias_1.addresses)
+... )
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account_1.name
+FROM user_account AS user_account_1
+JOIN address ON user_account_1.id = address.user_id
+

# ON 조건 확대

relation()으로 생성된 ON 절에 조건을 추가할 수 있습니다. 이 기능은 관계된 경로에 대한 특정 조인의 범위를 신속하게 제한하는 방법뿐만 아니라 마지막 섹션에서 소개하는 로더 전략 구성과 같은 사용 사례에도 유용합니다.
PropComparator.and_() 메서드는 AND를 통해 JOIN의 ON 절에 결합되는 일련의 SQL 식을 위치적으로 허용합니다. 예를 들어,
UserAddress을 활용하여 ON 기준을 특정 이메일 주소로만 제한하려는 경우 이와 같습니다.

>>> stmt = (
+...   select(User.fullname).
+...   join(User.addresses.and_(Address.email_address == 'pearl.krabs@gmail.com'))
+... )
+
+>>> session.execute(stmt).all()
+[('Pearl Krabs',)]
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.fullname
+FROM user_account
+JOIN address ON user_account.id = address.user_id AND address.email_address = ?
+[...] ('pearl.krabs@gmail.com',)
+

# EXISTS has() , and()

EXISTS 서브쿼리들 섹션에서는 SQL EXISTS 키워드를 스칼라 서브 쿼리, 상호연관 쿼리 섹션과 함께 소개했습니다.
relationship() 은 관계 측면에서 공통적으로 서브쿼리를 생성하는데 사용할 수 있는 일부 도움을 제공합니다.


User.addresses와 같은 1:N (one-to-many) 관계의 경우 PropComparator.any()를 사용하여 user_account테이블과 다시 연결되는 주소 테이블에 서브쿼리를 생성할 수 있습니다. 이 메서드는 하위 쿼리와 일치하는 행을 제한하는 선택적 WHERE 기준을 허용합니다.

>>> stmt = (
+...   select(User.fullname).
+...   where(User.addresses.any(Address.email_address == 'pearl.krabs@gmail.com'))
+... )
+
+>>> session.execute(stmt).all()
+[('Pearl Krabs',)]
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.fullname
+FROM user_account
+WHERE EXISTS (SELECT 1
+FROM address
+WHERE user_account.id = address.user_id AND address.email_address = ?)
+[...] ('pearl.krabs@gmail.com',)
+

이와 반대로 관련된 데이터가 없는 객체를 찾는 것은 ~User.addresses.any()을 사용하여 User 객체에 검색하는 방법입니다.

>>> stmt = (
+...   select(User.fullname).
+...   where(~User.addresses.any())
+... )
+
+>>> session.execute(stmt).all()
+[('Patrick McStar',), ('Squidward Tentacles',), ('Eugene H. Krabs',)]
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.fullname
+FROM user_account
+WHERE NOT (EXISTS (SELECT 1
+FROM address
+WHERE user_account.id = address.user_id))
+[...] ()
+
+

PropComparator.has() 메서드는 PropComparator.any()와 비슷한 방식으로 작동하지만, N:1 (Many-to-one) 관계에 사용됩니다.
+예시로 "pearl"에 속하는 모든 Address 객체를 찾으려는 경우 이와 같습니다.

>>> stmt = (
+...   select(Address.email_address).
+...   where(Address.user.has(User.name=="pkrabs"))
+... )
+
+>>> session.execute(stmt).all()
+[('pearl.krabs@gmail.com',), ('pearl@aol.com',)]
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.email_address
+FROM address
+WHERE EXISTS (SELECT 1
+FROM user_account
+WHERE user_account.id = address.user_id AND user_account.name = ?)
+[...] ('pkrabs',)
+

# 관계 연산자

relationship()와 함께 제공되는 SQL 생성 도우미에는 다음과 같은 몇 가지 종류가 있습니다.

  • N : 1 (Many-to-one) 비교
    +특정 객체 인스턴스를 N : 1 관계와 비교하여 대상 엔티티의 외부 키가 지정된 객체의 기본 키값과 일치하는 행을 선택할 수 있습니다.
>>> print(select(Address).where(Address.user == u1))
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE :param_1 = address.user_id
+
  • NOT N : 1 (Many-to-one) 비교
    +같지 않은 연산자(!=)를 사용할 수 있습니다.
>>> print(select(Address).where(Address.user != u1))
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE address.user_id != :user_id_1 OR address.user_id IS NULL
+
  • 객체가 1 : N (one-to-many) 컬렉션에 포함되어있는지 확인하는 방법입니다.
>>> print(select(User).where(User.addresses.contains(a1)))
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account
+WHERE user_account.id = :param_1
+
  • 객체가 1 : N 관계에서 특정 상위 항목에 있는지 확인하는 방법입니다.
    with_parent()은 주어진 상위 항목이 참조하는 행을 반환하는 비교를 생성합니다. 이는 == 연산자를 사용하는 것과 동일합니다.
>>> from sqlalchemy.orm import with_parent
+>>> print(select(Address).where(with_parent(u1, User.addresses)))
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id, address.email_address, address.user_id
+FROM address
+WHERE :param_1 = address.user_id
+

# Loading relationshiop의 종류


관계 로드 섹션에서는 매핑된 객체 인스턴스로 작업할 때 relationship()을 사용하여 매핑된 특성에 엑세스하면 이 컬렉션에 있어야 하는 객체를 로드하며, 컬렉션이 채워지지 않은 경우 lazy load가 발생한다는 개념을 도입했습니다.

Lazy loading 방식은 가장 유명한 ORM 패턴 중 하나이며, 가장 논란이 많은 ORM 패턴이기도 합니다.
+메모리에 있는 수십개의 ORM 객체가 각각 소수의 언로드 속성을 참조하는 경우, 객체의 일상적인 조작은 누적이 될 수 있는 많은 문제(N+1 Problem)를 암묵적으로 방출될 수 있습니다. 이러한 암시적 쿼리는 더 이상 사용할 수 없는 데이터베이스 변환을 시도할 때 또는 비동기화 같은 대체 동시성 패턴을 사용할 때 실제로 전혀 작동하지 않을 수 있습니다.

N + 1 Problem이란?
+쿼리 1번으로 N건의 데이터를 가져왔는데 원하는 데이터를 얻기 위해 이 N건의 데이터를 데이터 수 만큼 반복해서 2차적으로 쿼리를 수행하는 문제입니다.

lazy loading 방식은 사용 중인 동시성 접근법과 호환되고 다른 방법으로 문제를 일으키지 않을 때 매우 인기있고 유용한 패턴입니다. 이러한 이유로 SQLAlchemy의 ORM은 이러한 로드 동작을 제허하고 최적화할 수 있는 기능에 중점을 둡니다.

무엇보다 ORM의 lazy loading 방식을 효과적으로 사용하는 첫 번째 단계는 Application을 테스트하고 SQL을 확인하는 것입니다.
Session에서 분리된 객체에 대해 로드가 부적절하게 발생하는 경우, Loading relationship의 종류 사용을 검토해야 합니다.

Select.options() 메서드를 사용하여 SELECT 문과 연결할 수 있는 객체로 표시됩니다.

for user_obj in session.execute(
+    select(User).options(selectinload(User.addresses))
+).scalars():
+    user_obj.addresses  # access addresses collection already loaded
+

relationship.lazy를 사용하여 relationship()의 기본값으로 구성할 수도 있습니다.

from sqlalchemy.orm import relationship
+class User(Base):
+    __tablename__ = 'user_account'
+
+    addresses = relationship("Address", back_populates="user", lazy="selectin")
+

가장 많이 사용되는 loading 방식 몇 가지를 소개합니다.

참고
관계 로딩 기법의 2가지 기법
Configuring Loader Strategies at Mapping Time - relationship() 구성에 대한 세부정보
Relationship Loading with Loader Options - 로더에 대한 세부정보


# Select IN loading 방식

최신 SQLAlchemy에서 가장 유용한 로딩방식 옵션은 selectinload()입니다. 이 옵션은 관련 컬렉션을 참조하는 객체 집합의 문제인 가장 일반적인 형태의 "N + 1 Problem"문제를 해결합니다.
+대부분의 경우 JOIN 또는 하위 쿼리를 도입하지 않고 관련 테이블에 대해서만 내보낼 수 있는 SELET 양식을 사용하여 이 작업을 수행합니다. 또한 컬렉션이 로드되지 않은 상위 객체에 대한 쿼리만 수행합니다.
+아래 예시는 User 객체와 관련된 Address 객체를 selectinload()하여 보여줍니다.
Session.execute() 호출하는 동안 데이터베이스에서는 두 개의 SELECT 문이 생성되고 두 번째는 관련 Address 객체를 가져오는 것입니다.

>>> from sqlalchemy.orm import selectinload
+>>> stmt = (
+...   select(User).options(selectinload(User.addresses)).order_by(User.id)
+... )
+>>> for row in session.execute(stmt):
+...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
+spongebob  (spongebob@sqlalchemy.org)
+sandy  (sandy@sqlalchemy.org, sandy@squirrelpower.org)
+patrick  ()
+squidward  ()
+ehkrabs  ()
+pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.id
+[...] ()
+SELECT address.user_id AS address_user_id, address.id AS address_id,
+address.email_address AS address_email_address
+FROM address
+WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
+[...] (1, 2, 3, 4, 5, 6)
+

# Joined Loading 방식

Joined Loading은 SQLAlchemy에서 가장 오래됬으며, 이 방식은 eager loading의 일종으로 joined eager loading이라고도 합니다. N : 1 관계의 객체를 로드하는 데 가장 적합하며, +relationship()에 명시된 테이블을 SELECT JOIN하여 모든 테이블의 데이터들을 한꺼번에 가져오는 방식으로 Address 객체에 연결된 사용자가 있는 다음과 같은 경우에 OUTER JOIN이 아닌 INNER JOIN을 사용할 수 있습니다.

>>> from sqlalchemy.orm import joinedload
+>>> stmt = (
+...   select(Address).options(joinedload(Address.user, innerjoin=True)).order_by(Address.id)
+... )
+>>> for row in session.execute(stmt):
+...     print(f"{row.Address.email_address} {row.Address.user.name}")
+
+spongebob@sqlalchemy.org spongebob
+sandy@sqlalchemy.org sandy
+sandy@squirrelpower.org sandy
+pearl.krabs@gmail.com pkrabs
+pearl@aol.com pkrabs
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id, address.email_address, address.user_id, user_account_1.id AS id_1,
+user_account_1.name, user_account_1.fullname
+FROM address
+JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
+ORDER BY address.id
+[...] ()
+

joinedload()는 1 : N 관계를 의미하는 컬렉션에도 사용되지만 중접 컬렉션 및 더 큰 컬렉션이므로 selectinload() 처럼 사례별로 평가해야 하는 것과 같은 다른 옵션과 비교 합니다.

SELECT 쿼리문의 WHERE 및 ORDER BY 기준은 joinload()에 의해 렌더링된 테이블을 대상으로 하지 않는다는 점에 유의하는 것이 중요합니다. 위 SQL 쿼리에서 직접 주소를 지정할 수 없는 *익명 별칭**이 user_account테이블에 적용된 것을 볼 수 있습니다. 이 개념은 Zen of joined Eager Loading 섹션에서 더 자세히 설명합니다.

joinedload()에 의해 ON 절은 이전 ON 조건 확대에서 설명한 방법 joinedload()을 사용하여 직접 영향을 받을 수 있습니다.

참고
+일반적인 경우에는 "N + 1 problem"가 훨씬 덜 만연하기 때문에 다대일 열망 로드가 종종 필요하지 않다는 점에 유의하는 것이 중요합니다. 많은 객체가 모두 동일한 관련 객체를 참조하는 경우(예: Address 각각 동일한 참조하는 많은 객체) 일반 지연 로드를 사용하여 User객체에 대해 SQL이 한 번만 내보내 집니다. 지연 로드 루틴은 Session가능한 경우 SQL을 내보내지 않고 현재 기본 키로 관련 객체를 조회 합니다.


# Explicit Join + Eager load 방식

일반적인 사용 사례는 contains_eager()옵션을 사용하며, 이 옵션은 JOIN을 직접 설정했다고 가정하고 대신 COLUMNS 절의 추가 열이 반환된 각 객체의 관련 속성에 로드해야 한다는 점을 제외하고는 joinedload() 와 매우 유사합니다.

>>> from sqlalchemy.orm import contains_eager
+
+>>> stmt = (
+...   select(Address).
+...   join(Address.user).
+...   where(User.name == 'pkrabs').
+...   options(contains_eager(Address.user)).order_by(Address.id)
+... )
+
+>>> for row in session.execute(stmt):
+...     print(f"{row.Address.email_address} {row.Address.user.name}")
+
+pearl.krabs@gmail.com pkrabs
+pearl@aol.com pkrabs
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.id, user_account.name, user_account.fullname,
+address.id AS id_1, address.email_address, address.user_id
+FROM address JOIN user_account ON user_account.id = address.user_id
+WHERE user_account.name = ? ORDER BY address.id
+[...] ('pkrabs',)
+

위에서 user_account.name을 필터링하고 user_account의 반환된 Address.user속성으로 로드했습니다.
joinedload()를 별도로 적용했다면 불필요하게 두 번 조인된 SQL 쿼리가 생성되었을 것입니다.

>>> stmt = (
+...   select(Address).
+...   join(Address.user).
+...   where(User.name == 'pkrabs').
+...   options(joinedload(Address.user)).order_by(Address.id)
+... )
+>>> print(stmt)  # SELECT has a JOIN and LEFT OUTER JOIN unnecessarily
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT address.id, address.email_address, address.user_id,
+user_account_1.id AS id_1, user_account_1.name, user_account_1.fullname
+FROM address JOIN user_account ON user_account.id = address.user_id
+LEFT OUTER JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
+WHERE user_account.name = :name_1 ORDER BY address.id
+

참고
관계 로딩 기법의 2가지 기법
Zen of joined Eager Loading - 해당 로딩 방식에 대한 세부정보
Routing Explicit Joins/Statements into Eagerly Loaded Collections - using contains_eager()


# 로더 경로 설정

PropComparator.and_() 방법은 실제로 대부분의 로더 옵션에서 일반적으로 사용할 수 있습니다. +예를 들어 sqlalchemy.org도메인에서 사용자 이름과 이메일 주소를 다시 로드하려는 경우 selectinload() 전달된 인수에 PropComparator.and_()를 적용하여 다음 조건을 제한할 수 있습니다.

>>> from sqlalchemy.orm import selectinload
+>>> stmt = (
+...   select(User).
+...   options(
+...       selectinload(
+...           User.addresses.and_(
+...             ~Address.email_address.endswith("sqlalchemy.org")
+...           )
+...       )
+...   ).
+...   order_by(User.id).
+...   execution_options(populate_existing=True)
+... )
+
+>>> for row in session.execute(stmt):
+...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
+
+spongebob  ()
+sandy  (sandy@squirrelpower.org)
+patrick  ()
+squidward  ()
+ehkrabs  ()
+pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)
+

위 코드는 다음 쿼리를 실행하는 것과 같습니다.

SELECT user_account.id, user_account.name, user_account.fullname
+FROM user_account ORDER BY user_account.id
+[...] ()
+SELECT address.user_id AS address_user_id, address.id AS address_id,
+address.email_address AS address_email_address
+FROM address
+WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
+AND (address.email_address NOT LIKE '%' || ?)
+[...] (1, 2, 3, 4, 5, 6, 'sqlalchemy.org')
+

위에서 매우 중요한 점은 .execution_options(populate_existing=True) 옵션이 추가되었다는 점 입니다.
+행을 가져올 때 적용되는 이 옵션은 로더 옵션이 이미 로드된 객체의 기존 컬렉션 내용을 대체해야 함을 나타냅니다.
Session객체로 반복 작업하므로 위에서 로드되는 객체는 본 튜토리얼의 ORM 섹션 시작 시 처음 유지되었던 것과 동일한 Python 인스턴스입니다.


# raise loading 방식

raiseload()옵션은 일반적으로 느린 대신 오류를 발생시켜 N + 1 문제가 발생하는 것을 완전히 차단하는데 사용됩니다.
+예로 두 가지 변형 모델이 있습니다. SQL이 필요한 lazy load 와 현재 Session만 참조하면 되는 작업을 포함한 모든 "load" 작업을 차단하는 raiseload.sql_only 옵션입니다.

class User(Base):
+    __tablename__ = 'user_account'
+
+    # ... Column mappings
+
+    addresses = relationship("Address", back_populates="user", lazy="raise_on_sql")
+
+
+class Address(Base):
+    __tablename__ = 'address'
+
+    # ... Column mappings
+
+    user = relationship("User", back_populates="addresses", lazy="raise_on_sql")
+

이러한 매핑을 사용하면 응용 프로그램이 'lazy loading'에 차단되어 특정 쿼리에 로더 전략을 지정해야 합니다.

u1 = s.execute(select(User)).scalars().first()
+u1.addresses
+sqlalchemy.exc.InvalidRequestError: 'User.addresses' is not available due to lazy='raise_on_sql'
+

예외는 이 컬렉션을 대신 먼저 로드해야 함을 나타냅니다.

u1 = s.execute(select(User).options(selectinload(User.addresses))).scalars().first()
+

lazy="raise_on_sql" 옵션은 N : 1 관계에도 현명하게 시도합니다.
+위에서 Address.user속성이 Address에 로드되지 않았지만 해당 User 객체가 동일한 Session에 있는 경우 "raiseload"은 오류를 발생시키지 않습니다.

참고
raiseload를 사용하여 원치 않는 lazy loading 방지
relatonship에서 lazy loading 방지

+ + + diff --git a/tutorial/index.html b/tutorial/index.html new file mode 100644 index 0000000..6c79c37 --- /dev/null +++ b/tutorial/index.html @@ -0,0 +1,39 @@ + + + + + + Tutorial | 파이썬 개발자를 위한 SQLAlchemy + + + + + + + + + + + + + +

# Tutorial

이 문서는 SQLAlchemy 1.4/2.0 Tutorial (opens new window)를 번역 및 정리한 글입니다.

기존 공식 문서는 보기 어렵고, 너무 많은 내용이 담겨있습니다. 또한 초보자가 보기에 너무 어렵다는 생각이 들었습니다.
+이에 SQLAlchemy Tutorial 문서를 같이 공부할 겸, 누구나 쉽게 볼 수 있고 정리하면 어떨까라는 생각으로 이 글 (opens new window)에서 같이 작업할 사람들이 모이게 되었습니다.

한 달이 조금 넘는 기간동안, 매주 돌아가며 공식 Tutorial 문서를 한 챕터씩 맡아서 작업했습니다.
+서로 리뷰해주며 글을 다듬고, 이해가 안가는 부분을 서로 물어보기도 했습니다.
+이 문서 모음들은 이러한 과정 끝에 나온 결과물입니다. 저희가 스터디한 흔적이기도 합니다.

여전히 부족한 부분이 많고, 틀린 부분이 있을 수 있습니다.
+이런 부분 발견하시면 언제든 기여해주세요. 늘 환영하고 있습니다.

아래와 같은 분들이 참여해주셨습니다.

+ + +