8 |
9 |
--------------------------------------------------------------------------------
/Clean Code/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Clean Code/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Clean Code/2장-의미 있는 이름.md:
--------------------------------------------------------------------------------
1 | # 의미 있는 이름이란?
2 |
3 | ## 인상 깊었던 내용
4 |
5 | **의도를 분명히 밝혀라**
6 | 의도를 분명히 밝힌다는 것은 무슨 의미인가? 어떻게 분명히 할 수 있는가? 좋은 이름으로 만드는 것이 첫번째이다.
7 |
8 | `코드는 단순성이 아니라 코드의 함축성이다.` 코드 맥락이 코드 자체에 명시적으로 드러나지 않는다.
9 |
10 | **그릇된 정보를 피하라**
11 | 일관성이 떨어지는 표기법은 `그릇된 정보`다.
12 |
13 | **의미 있게 구분하라**
14 |
15 | `getActiveAccount()`
16 | `getActiveAccounts()`
17 | `getActiveAccountInfo()`
18 |
19 | 어느 함수를 호출할지 어떻게 알까? 읽는 사람이 차이를 알도록 이름을 지어라.
20 |
21 | **한 개념에 한 단어를 사용하라**
22 | 추상적인 개념 하나에 단어 하나를 선택해 이를 고수한다. 그러므로 일관성 있는 어휘를 사용해 의미 있는 이름을 표현하자.
23 |
24 | ## 왜 인상 깊었는지?
25 |
26 | 대다수 말하는 내용은 의미있는이름을 만들어야 하는 이유에 대해서 설명하고 있다고 생각된다. 좋은 내용임은 알지만, 현실 코딩에서 이 부분을 이해하고 사용할 수 있을까?여전히 쉽지 않은 문제이고, 의도적인 수련이 필요하다고 판단된다.
27 |
28 |
29 | ## 인상 깊었던 내용에 대해서 표현할 수 있는 코드
30 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/Chapter06_RxAndroid.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/Chapter06_RxAndroid.md
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 | /app/
12 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxAndroidExample/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxAndroidExample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 02 16:45:25 KST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxAndroidExample/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJava 3주차_또치.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJava 3주차_또치.pdf
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJava 4주차_가온.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJava 4주차_가온.pdf
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJava 6주차_디버깅과 예외처리-compressed.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJava 6주차_디버깅과 예외처리-compressed.pdf
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.gradle/4.0/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.gradle/4.0/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJavaStudy/.gradle/4.0/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.gradle/buildOutputCleanup/built.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJavaStudy/.gradle/buildOutputCleanup/built.bin
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 02 16:34:48 KST 2018
2 | gradle.version=4.0
3 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.gradle/buildOutputCleanup/cache.properties.lock:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/README.md:
--------------------------------------------------------------------------------
1 | # Goal
2 |
3 | #1.
4 | - Observable 클래스를 명확하게 이해합니다. 특히 뜨거운 Observable(Hot Observable)과 차가운 Observable(Cold Observable)의 개념을 꼭 이해
5 | - 간단한 예제로 map(), filter(), reduce(), flatMap() 함수의 사용법을 익힙니다.
6 | - 생성 연산자, 결합 연산자, 변환 연산자 등 카테고리별 주요 함수를 공부
7 | - 스케줄러의 의미를 배우고 subscribeOn()과 observeOn() 함수의 차이를 알아 둡니다.
8 | - 그 밖의 디버깅, 흐름 제어 함수를 익힌다.
9 |
10 | #2.
11 | Example Practice
12 |
13 |
14 |
15 | ## Reference
16 | > 유동환님 저자의 RxJava 프로그래밍
17 |
18 | (유동환님의 허락 하에 일부 내용 정리중...)
19 | [LenKIM_TIL_자료](https://github.com/LenKIM/TIL_Today_I_Learned/tree/master/FP(FunctionalProgramming)/RxJAVA)
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJavaStudy/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jul 06 23:10:43 KST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
7 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'RxJavaStudy'
2 |
3 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/src/test/java/CombinationOperator.java:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/src/test/java/ReduceTest.java:
--------------------------------------------------------------------------------
1 | import io.reactivex.Maybe;
2 | import io.reactivex.Observable;
3 | import org.junit.Test;
4 |
5 | public class ReduceTest {
6 |
7 | @Test
8 | public void Testreduce() {
9 |
10 | String[] balls = {"1", "3", "5"};
11 | Maybe source = Observable.fromArray(balls)
12 | .reduce((ball1, ball2) -> ball2 + "(" + ball1 + ")");
13 |
14 | source.test().assertResult("5(3(1))");
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/src/test/java/Test.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/RxJava 프로그래밍/RxJavaStudy/src/test/java/Test.java
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/src/test/java/common/GsonHelper.java:
--------------------------------------------------------------------------------
1 | package common;
2 |
3 | import com.google.gson.JsonParser;
4 |
5 | public class GsonHelper {
6 | public static String parseValue(String json, String key) {
7 | return new JsonParser().parse(json)
8 | .getAsJsonObject()
9 | .get(key)
10 | .getAsString();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/RxJava 프로그래밍/RxJavaStudy/src/test/java/common/ShapeCannotFlipException.java:
--------------------------------------------------------------------------------
1 | package common;
2 |
3 | public class ShapeCannotFlipException extends Exception {
4 | }
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/add-enum-value.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs MODIFY COLUMN status
2 | ENUM('NEW', 'IN PROGRESS', 'FIXED', 'DUPLICATE');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/create-table-check.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | -- other columns
3 | status VARCHAR(20) CHECK (status IN ('NEW', 'IN PROGRESS', 'FIXED'))
4 | );
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/create-table-enum.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | -- other columns
3 | status ENUM('NEW', 'IN PROGRESS', 'FIXED'),
4 | );
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/distinct.sql:
--------------------------------------------------------------------------------
1 | SELECT DISTINCT status FROM Bugs;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/information-schema.sql:
--------------------------------------------------------------------------------
1 | SELECT column_type
2 | FROM information_schema.columns
3 | WHERE table_schema = 'bugtracker_schema'
4 | AND table_name = 'bugs'
5 | AND column_name = 'status';
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/anti/remove-enum-value.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs MODIFY COLUMN status
2 | ENUM('NEW', 'IN PROGRESS', 'CODE COMPLETE', 'VERIFIED');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/intro/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE PersonalContacts (
2 | -- other columns
3 | salutation VARCHAR(4)
4 | CHECK (salutation IN ('Mr.', 'Mrs.', 'Ms.', 'Dr.', 'Rev.')),
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/obj/insert-invalid.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Bugs (status) VALUES ('NEW'); -- OK
2 |
3 | INSERT INTO Bugs (status) VALUES ('BANANA'); -- Error!
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/create-lookup-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugStatus (
2 | status VARCHAR(20) PRIMARY KEY
3 | );
4 |
5 | INSERT INTO BugStatus (status) VALUES ('NEW'), ('IN PROGRESS'), ('FIXED');
6 |
7 | CREATE TABLE Bugs (
8 | -- other columns
9 | status VARCHAR(20),
10 | FOREIGN KEY (status) REFERENCES BugStatus(status)
11 | ON UPDATE CASCADE
12 | );
13 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/inactive.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE BugStatus ADD COLUMN active
2 | ENUM('INACTIVE', 'ACTIVE') NOT NULL DEFAULT 'ACTIVE';
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/insert-value.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO BugStatus (status) VALUES ('DUPLICATE');
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/query-canonical-values.sql:
--------------------------------------------------------------------------------
1 | SELECT status FROM BugStatus ORDER BY status;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/select-active.sql:
--------------------------------------------------------------------------------
1 | SELECT status FROM BugStatus WHERE active = 'ACTIVE';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/update-inactive.sql:
--------------------------------------------------------------------------------
1 | UPDATE BugStatus SET active = 'INACTIVE' WHERE status = 'DUPLICATE';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/31-Flavors/soln/update-value.sql:
--------------------------------------------------------------------------------
1 | UPDATE BugStatus SET status = 'INVALID' WHERE status = 'BOGUS';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/count.sql:
--------------------------------------------------------------------------------
1 | SELECT date_reported, COUNT(*) AS bugs_per_date
2 | FROM (SELECT DISTINCT issue_id, attr_value AS date_reported
3 | FROM IssueAttributes
4 | WHERE attr_name IN ('date_reported', 'report_date'))
5 | GROUP BY date_reported;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/data-types.sql:
--------------------------------------------------------------------------------
1 | SELECT issue_id, COALESCE(attr_value_date, attr_value_datetime,
2 | attr_value_integer, attr_value_numeric, attr_value_float,
3 | attr_value_string, attr_value_text) AS "date_reported"
4 | FROM IssueAttributes
5 | WHERE attr_name = 'date_reported';
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/foreign-key-eav.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IssueAttributes (
2 | issue_id BIGINT UNSIGNED NOT NULL,
3 | attr_name VARCHAR(100) NOT NULL,
4 | attr_value VARCHAR(100),
5 | FOREIGN KEY (attr_value) REFERENCES BugStatus(status)
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/foreign-key-plain.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Issues (
2 | issue_id SERIAL PRIMARY KEY,
3 | -- other columns
4 | status VARCHAR(20) NOT NULL DEFAULT 'NEW',
5 | FOREIGN KEY (status) REFERENCES BugStatus(status)
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/insert-eav.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO IssueAttributes (issue_id, attr_name, attr_value)
2 | VALUES (1234, 'date_reported', 'banana'); -- Not an error!
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/insert-plain.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Issues (date_reported) VALUES ('banana'); -- ERROR!
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/query-eav.sql:
--------------------------------------------------------------------------------
1 | SELECT issue_id, attr_value AS "date_reported"
2 | FROM IssueAttributes
3 | WHERE attr_name = 'date_reported';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/query-plain.sql:
--------------------------------------------------------------------------------
1 | SELECT issue_id, date_reported FROM Issues;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/anti/reconstruct.sql:
--------------------------------------------------------------------------------
1 | SELECT i.issue_id,
2 | i1.attr_value AS "date_reported",
3 | i2.attr_value AS "status",
4 | i3.attr_value AS "priority",
5 | i4.attr_value AS "description"
6 | FROM Issues AS i
7 | LEFT OUTER JOIN IssueAttributes AS i1
8 | ON i.issue_id = i1.issue_id AND i1.attr_name = 'date_reported'
9 | LEFT OUTER JOIN IssueAttributes AS i2
10 | ON i.issue_id = i2.issue_id AND i2.attr_name = 'status'
11 | LEFT OUTER JOIN IssueAttributes AS i3
12 | ON i.issue_id = i3.issue_id AND i3.attr_name = 'priority';
13 | LEFT OUTER JOIN IssueAttributes AS i4
14 | ON i.issue_id = i4.issue_id AND i4.attr_name = 'description';
15 | WHERE i.issue_id = 1234;
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/intro/count.sql:
--------------------------------------------------------------------------------
1 | SELECT date_reported, COUNT(*)
2 | FROM Bugs
3 | GROUP BY date_reported;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/create-blob-tables.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Issues (
2 | issue_id SERIAL PRIMARY KEY,
3 | reported_by BIGINT UNSIGNED NOT NULL,
4 | product_id BIGINT UNSIGNED,
5 | priority VARCHAR(20),
6 | version_resolved VARCHAR(20),
7 | status VARCHAR(20),
8 | issue_type VARCHAR(10), -- BUG or FEATURE
9 | attributes TEXT NOT NULL, -- all dynamic attributes for the row
10 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id),
11 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
12 | );
13 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/create-sti-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Issues (
2 | issue_id SERIAL PRIMARY KEY,
3 | reported_by BIGINT UNSIGNED NOT NULL,
4 | product_id BIGINT UNSIGNED,
5 | priority VARCHAR(20),
6 | version_resolved VARCHAR(20),
7 | status VARCHAR(20),
8 | issue_type VARCHAR(10), -- BUG or FEATURE
9 | severity VARCHAR(20), -- only for bugs
10 | version_affected VARCHAR(20), -- only for bugs
11 | sponsor VARCHAR(50), -- only for feature requests
12 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id)
13 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
14 | );
15 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/insert-concrete.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO FeatureRequests (issue_id, severity) VALUES ( ... ); -- ERROR!
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/post-process.php:
--------------------------------------------------------------------------------
1 | query(
5 | "SELECT issue_id, attr_name, attr_value
6 | FROM IssueAttributes
7 | WHERE issue_id = 1234");
8 | while ($row = $stmt->fetch()) {
9 | $id = $row['issue_id'];
10 | $field = $row['attr_name'];
11 | $value = $row['attr_value'];
12 | if (!array_key_exists($id, $objects)) {
13 | $objects[$id] = new stdClass();
14 | }
15 | $objects[$id]->$field = $value;
16 | }
17 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/post-process.sql:
--------------------------------------------------------------------------------
1 | SELECT issue_id, attr_name, attr_value
2 | FROM IssueAttributes
3 | WHERE issue_id = 1234;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/select-class.sql:
--------------------------------------------------------------------------------
1 | SELECT i.*, b.*, f.*
2 | FROM Issues AS i
3 | LEFT OUTER JOIN Bugs AS b USING (issue_id)
4 | LEFT OUTER JOIN FeatureRequests AS f USING (issue_id);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/EAV/soln/view-concrete.sql:
--------------------------------------------------------------------------------
1 | CREATE VIEW Issues AS
2 | SELECT b.issue_id, b.reported_by, ... 'bug' AS issue_type
3 | FROM Bugs AS b
4 | UNION ALL
5 | SELECT f.issue_id, f.reported_by, ... 'feature' AS issue_type
6 | FROM FeatureRequests AS f;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/equals-null.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to = NULL;
2 |
3 | SELECT * FROM Bugs WHERE assigned_to <> NULL;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/expression.sql:
--------------------------------------------------------------------------------
1 | SELECT hours + 10 FROM Bugs;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/parameter.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to = ?;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/search-not.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE NOT (assigned_to = 123);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to = 123;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/special-create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY,
3 | -- other columns
4 | assigned_to BIGINT UNSIGNED NOT NULL,
5 | hours NUMERIC(9,2) NOT NULL,
6 | FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id)
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/special-insert.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Bugs (assigned_to, hours) VALUES (-1, -1);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/anti/special-select.sql:
--------------------------------------------------------------------------------
1 | SELECT AVG( hours ) AS average_hours_per_bug FROM Bugs
2 | WHERE hours <> -1;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/intro/full-name.sql:
--------------------------------------------------------------------------------
1 | SELECT first_name || ' ' || last_name AS full_name FROM Accounts;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/intro/middle-name.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Accounts ADD COLUMN middle_initial CHAR(2);
2 |
3 | UPDATE Accounts SET middle_initial = 'J.' WHERE account_id = 123;
4 | UPDATE Accounts SET middle_initial = 'C.' WHERE account_id = 321;
5 |
6 | SELECT first_name || ' ' || middle_initial || ' ' || last_name AS full_name
7 | FROM Accounts;
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/soln/coalesce.sql:
--------------------------------------------------------------------------------
1 | SELECT first_name || COALESCE(' ' || middle_initial || ' ', ' ') || last_name
2 | AS full_name
3 | FROM Accounts;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/soln/is-distinct-from-parameter.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to IS DISTINCT FROM ?;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/soln/is-distinct-from.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to IS NULL OR assigned_to <> 1;
2 |
3 | SELECT * FROM Bugs WHERE assigned_to IS DISTINCT FROM 1;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Fear-Unknown/soln/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE assigned_to IS NULL;
2 |
3 | SELECT * FROM Bugs WHERE assigned_to IS NOT NULL;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/anti/distinct.sql:
--------------------------------------------------------------------------------
1 | -- START:distinct
2 | SELECT DISTINCT date_reported, reported_by FROM Bugs;
3 | -- END:distinct
4 | -- START:groupby
5 | SELECT date_reported, reported_by FROM Bugs
6 | GROUP BY date_reported, reported_by;
7 | -- END:groupby
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/anti/groupbyproduct.sql:
--------------------------------------------------------------------------------
1 | -- START:standard
2 | SELECT product_id, MAX(date_reported) AS latest
3 | FROM Bugs JOIN BugsProducts USING (bug_id)
4 | GROUP BY product_id;
5 | -- END:standard
6 | -- START:withbugid
7 | SELECT product_id, MAX(date_reported) AS latest, bug_id
8 | FROM Bugs JOIN BugsProducts USING (bug_id)
9 | GROUP BY product_id;
10 | -- END:withbugid
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/anti/maxandmin.sql:
--------------------------------------------------------------------------------
1 | SELECT product_id, MAX(date_reported) AS latest,
2 | MIN(date_reported) AS earliest, bug_id
3 | FROM Bugs JOIN BugsProducts USING (bug_id)
4 | GROUP BY product_id;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/anti/sumbyproduct.sql:
--------------------------------------------------------------------------------
1 | SELECT product_id, SUM(hours) AS total_project_estimate, bug_id
2 | FROM Bugs JOIN BugsProducts USING (bug_id)
3 | GROUP BY product_id;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/legit/functional.sql:
--------------------------------------------------------------------------------
1 | SELECT b.reported_by, a.account_name
2 | FROM Bugs b JOIN Accounts a ON (b.reported_by = a.account_id)
3 | GROUP BY b.reported_by;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/derived-table-no-duplicates.sql:
--------------------------------------------------------------------------------
1 | SELECT m.product_id, m.latest, MAX(b1.bug_id) AS latest_bug_id
2 | FROM Bugs b1 JOIN
3 | (SELECT product_id, MAX(date_reported) AS latest
4 | FROM Bugs b2 JOIN BugsProducts USING (bug_id)
5 | GROUP BY product_id) m
6 | ON (b1.date_reported = m.latest)
7 | GROUP BY m.product_id, m.latest;
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/derived-table.sql:
--------------------------------------------------------------------------------
1 | SELECT m.product_id, m.latest, b1.bug_id
2 | FROM Bugs b1 JOIN BugsProducts bp1 USING (bug_id)
3 | JOIN (SELECT bp2.product_id, MAX(b2.date_reported) AS latest
4 | FROM Bugs b2 JOIN BugsProducts bp2 USING (bug_id)
5 | GROUP BY bp2.product_id) m
6 | ON (bp1.product_id = m.product_id AND b1.date_reported = m.latest);
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/extra-aggregate.sql:
--------------------------------------------------------------------------------
1 | SELECT product_id, MAX(date_reported) AS latest,
2 | MAX(bug_id) AS latest_bug_id
3 | FROM Bugs JOIN BugsProducts USING (bug_id)
4 | GROUP BY product_id;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/group-concat-mysql.sql:
--------------------------------------------------------------------------------
1 | SELECT product_id, MAX(date_reported) AS latest
2 | GROUP_CONCAT(bug_id) AS bug_id_list,
3 | FROM Bugs JOIN BugsProducts USING (bug_id)
4 | GROUP BY product_id;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/group-concat-pgsql.sql:
--------------------------------------------------------------------------------
1 | CREATE AGGREGATE GROUP_ARRAY (
2 | BASETYPE = ANYELEMENT,
3 | SFUNC = ARRAY_APPEND,
4 | STYPE = ANYARRAY,
5 | INITCOND = '{}'
6 | );
7 |
8 | SELECT product_id, MAX(date_reported) AS latest,
9 | ARRAY_TO_STRING(GROUP_ARRAY(bug_id), ',') AS bug_id_list
10 | FROM Bugs JOIN BugsProducts USING (bug_id)
11 | GROUP BY product_id;
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/notexists.sql:
--------------------------------------------------------------------------------
1 | SELECT bp1.product_id, b1.date_reported AS latest, b1.bug_id
2 | FROM Bugs b1 JOIN BugsProducts bp1 USING (bug_id)
3 | WHERE NOT EXISTS
4 | (SELECT * FROM Bugs b2 JOIN BugsProducts bp2 USING (bug_id)
5 | WHERE bp1.product_id = bp2.product_id
6 | AND b1.date_reported < b2.date_reported);
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Groups/soln/outer-join.sql:
--------------------------------------------------------------------------------
1 | SELECT bp1.product_id, b1.date_reported AS latest, b1.bug_id
2 | FROM Bugs b1 JOIN BugsProducts bp1 ON (b1.bug_id = bp1.bug_id)
3 | LEFT OUTER JOIN (Bugs AS b2 JOIN BugsProducts AS bp2 ON (b2.bug_id = bp2.bug_id))
4 | ON (bp1.product_id = bp2.product_id AND (b1.date_reported < b2.date_reported
5 | OR b1.date_reported = b2.date_reported AND b1.bug_id < b2.bug_id))
6 | WHERE b2.bug_id IS NULL;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/anti/ambiguous.sql:
--------------------------------------------------------------------------------
1 | SELECT b.id, a.id
2 | FROM Bugs b
3 | JOIN Accounts a ON (b.assigned_to = a.id)
4 | WHERE b.status = 'OPEN';
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/anti/id-redundant.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | id SERIAL PRIMARY KEY,
3 | bug_id VARCHAR(10) UNIQUE,
4 | description VARCHAR(1000),
5 | -- . . .
6 | );
7 |
8 | INSERT INTO Bugs (bug_id, description, ...)
9 | VALUES ('VIS-078', 'crashes on save', ...);
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/anti/id-ubiquitous.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | id SERIAL PRIMARY KEY,
3 | description VARCHAR(1000),
4 | -- . . .
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/anti/join.sql:
--------------------------------------------------------------------------------
1 | -- START:on
2 | SELECT * FROM Bugs AS b JOIN BugsProducts AS bp ON (b.bug_id = bp.bug_id);
3 | -- END:on
4 | -- START:using
5 | SELECT * FROM Bugs JOIN BugsProducts USING (bug_id);
6 | -- END:using
7 | -- START:verbose
8 | SELECT * FROM Bugs AS b JOIN BugsProducts AS bp ON (b.id = bp.bug_id);
9 | -- END:vebose
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/anti/select-max.sql:
--------------------------------------------------------------------------------
1 | SELECT MAX(bug_id) + 1 AS next_bug_id FROM Bugs;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/intro/articletags.sql:
--------------------------------------------------------------------------------
1 | -- START:table
2 | CREATE TABLE ArticleTags (
3 | id SERIAL PRIMARY KEY,
4 | article_id BIGINT UNSIGNED NOT NULL,
5 | tag_id BIGINT UNSIGNED NOT NULL,
6 | FOREIGN KEY (article_id) REFERENCES Articles (id),
7 | FOREIGN KEY (tag_id) REFERENCES Tags (id)
8 | );
9 | -- END:table
10 | -- START:select
11 | SELECT tag_id, COUNT(*) AS articles_per_tag FROM ArticleTags WHERE tag_id = 327;
12 | -- END:select
13 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/soln/compound.sql:
--------------------------------------------------------------------------------
1 | -- START:table
2 | CREATE TABLE BugsProducts (
3 | bug_id BIGINT UNSIGNED NOT NULL,
4 | product_id BIGINT UNSIGNED NOT NULL,
5 | PRIMARY KEY (bug_id, product_id),
6 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
7 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
8 | );
9 | -- END:table
10 |
11 | -- START:insert
12 | INSERT INTO BugsProducts (bug_id, product_id)
13 | VALUES (1234, 1), (1234, 2), (1234, 3);
14 |
15 | INSERT INTO BugsProducts (bug_id, product_id)
16 | VALUES (1234, 1); -- error: duplicate entry
17 | --END:insert
18 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/soln/custom-primarykey.rb:
--------------------------------------------------------------------------------
1 | #---
2 | # Excerpted from "SQL Antipatterns",
3 | # published by The Pragmatic Bookshelf.
4 | # Copyrights apply to this code. It may not be used to create training material,
5 | # courses, books, articles, and the like. Contact us if you are in doubt.
6 | # We make no guarantees that this code is fit for any purpose.
7 | # Visit http://www.pragmaticprogrammer.com/titles/bksqla for more book information.
8 | #---
9 | class Bug < ActiveRecord::Base
10 | set_primary_key "bug_id"
11 | end
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/ID-Required/soln/foreignkey-name.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | -- . . .
3 | reported_by BIGINT UNSIGNED NOT NULL,
4 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id)
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/anti/add-column.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs ADD COLUMN date_due DATE;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/anti/drop-column.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs DROP COLUMN verified_by;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/anti/insert-mismatched.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Bugs VALUES (DEFAULT, CURDATE(), 'New bug', 'Test T987 fails...',
2 | NULL, 123, NULL, NULL, DEFAULT, 'Medium', NULL);
3 |
4 | -- SQLSTATE 21S01: Column count doesn't match value count at row 1
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/anti/ordinal.php:
--------------------------------------------------------------------------------
1 | query("SELECT * FROM Bugs WHERE bug_id = 1234");
3 | $row = $stmt->fetch();
4 | $hours = $row[10];
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/intro/join-alias.sql:
--------------------------------------------------------------------------------
1 | SELECT b.title, a.title AS salutation
2 | FROM Books b JOIN Authors a ON (b.author_id = a.author_id);
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/intro/join-wildcard.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Books b JOIN Authors a ON (b.author_id = a.author_id);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/legit/wildcard-one-table.sql:
--------------------------------------------------------------------------------
1 | SELECT b.*, a.first_name, a.email
2 | FROM Bugs b JOIN Accounts a
3 | ON (b.reported_by = a.account_id);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/obj/insert-explicit.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Accounts (account_name, first_name, last_name, email,
2 | password, portrait_image, hourly_rate) VALUES
3 | ('bkarwin', 'Bill', 'Karwin', 'bill@example.com', SHA2('xyzzy'), NULL, 49.95);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/obj/insert-implicit.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Accounts VALUES (DEFAULT,
2 | 'bkarwin', 'Bill', 'Karwin', 'bill@example.com', SHA2('xyzzy'), NULL, 49.95);
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/obj/select-explicit.sql:
--------------------------------------------------------------------------------
1 | SELECT bug_id, date_reported, summary, description, resolution,
2 | reported_by, assigned_to, verified_by, status, priority, hours
3 | FROM Bugs;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/obj/select-implicit.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/soln/insert-explicit.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Accounts (account_name, first_name, last_name, email,
2 | password_hash, portrait_image, hourly_rate)
3 | VALUES ('bkarwin', 'Bill', 'Karwin', 'bill@example.com',
4 | SHA2('xyzzy'), NULL, 49.95);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/soln/select-explicit.sql:
--------------------------------------------------------------------------------
1 | SELECT bug_id, date_reported, summary, description, resolution,
2 | reported_by, assigned_to, verified_by, status, priority, hours
3 | FROM Bugs;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Implicit-Columns/soln/yagni.sql:
--------------------------------------------------------------------------------
1 | SELECT date_reported, summary, description, resolution, status, priority
2 | FROM Bugs;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Index-Shotgun/anti/create-index.sql:
--------------------------------------------------------------------------------
1 | CREATE INDEX TelephoneBook ON Accounts(last_name, first_name);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Index-Shotgun/anti/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY,
3 | date_reported DATE NOT NULL,
4 | summary VARCHAR(80) NOT NULL,
5 | status VARCHAR(10) NOT NULL,
6 | hours NUMERIC(9,2),
7 | INDEX (bug_id), -- (1)
8 | INDEX (summary), -- (2)
9 | INDEX (hours), -- (3)
10 | INDEX (bug_id, date_reported, status) -- (4)
11 | );
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Index-Shotgun/anti/update-unindexed.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs SET status = 'OBSOLETE' WHERE date_reported < '2000-01-01';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Index-Shotgun/anti/update.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs SET status = 'FIXED' WHERE bug_id = 1234;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Index-Shotgun/soln/explain.sql:
--------------------------------------------------------------------------------
1 | EXPLAIN SELECT Bugs.*
2 | FROM Bugs
3 | JOIN (BugsProducts JOIN Products USING (product_id))
4 | USING (bug_id)
5 | WHERE summary LIKE '%crash%'
6 | AND product_name = 'Open RoundFile'
7 | ORDER BY date_reported DESC;
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Introduction/Makefile:
--------------------------------------------------------------------------------
1 | MYSQL=/opt/local/bin/mysql5
2 | USER=
3 | PASS=
4 | DB=test
5 | MYSQLCMD=$(MYSQL) -u$(USER) -p$(PASS) $(DB) --verbose
6 |
7 | all: setup
8 |
9 | setup:
10 | $(MYSQLCMD) -e "source setup.sql"
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/banana.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Products (product_id, product_name, account_id)
2 | VALUES (DEFAULT, 'Visual TurboBuilder', '12,34,banana');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/count.sql:
--------------------------------------------------------------------------------
1 | SELECT product_id, LENGTH(account_id) - LENGTH(REPLACE(account_id, ',', '')) + 1
2 | AS contacts_per_product
3 | FROM Products;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/create.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Products (
2 | product_id SERIAL PRIMARY KEY,
3 | product_name VARCHAR(1000),
4 | account_id VARCHAR(100), -- comma-separated list
5 | -- . . .
6 | );
7 |
8 | INSERT INTO Products (product_id, product_name, account_id)
9 | VALUES (DEFAULT, 'Visual TurboBuilder', '12,34');
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/length.sql:
--------------------------------------------------------------------------------
1 | UPDATE Products SET account_id = '10,14,18,22,26,30,34,38,42,46'
2 | WHERE product_id = 123;
3 |
4 | UPDATE Products SET account_id = '101418,222630,343842,467790'
5 | WHERE product_id = 123;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/regexp.sql:
--------------------------------------------------------------------------------
1 | -- START:where
2 | SELECT * FROM Products WHERE account_id REGEXP '[[:<:]]12[[:>:]]';
3 | -- END:where
4 | -- START:join
5 | SELECT * FROM Products AS p JOIN Accounts AS a
6 | ON p.account_id REGEXP '[[:<:]]' || a.account_id || '[[:>:]]'
7 | WHERE p.product_id = 123;
8 | -- END:join
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/remove.php:
--------------------------------------------------------------------------------
1 | query(
4 | "SELECT account_id FROM Products WHERE product_id = 123");
5 | $row = $stmt->fetch();
6 | $contact_list = $row['account_id'];
7 |
8 | // change list in PHP code
9 | $value_to_remove = "34";
10 | $contact_list = split(",", $contact_list);
11 | $key_to_remove = array_search($value_to_remove, $contact_list);
12 | unset($contact_list[$key_to_remove]);
13 | $contact_list = join(",", $contact_list);
14 |
15 | $stmt = $pdo->prepare(
16 | "UPDATE Products SET account_id = ?
17 | WHERE product_id = 123");
18 | $stmt->execute(array($contact_list));
19 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/anti/update.sql:
--------------------------------------------------------------------------------
1 | UPDATE Products
2 | SET account_id = account_id || ',' || 56
3 | WHERE product_id = 123;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/obj/create.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Products (
2 | product_id SERIAL PRIMARY KEY,
3 | product_name VARCHAR(1000),
4 | account_id BIGINT UNSIGNED,
5 | -- . . .
6 | FOREIGN KEY (account_id) REFERENCES Accounts(account_id)
7 | );
8 |
9 | INSERT INTO Products (product_id, product_name, account_id)
10 | VALUES (DEFAULT, 'Visual TurboBuilder', 12);
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/soln/create.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Contacts (
2 | product_id BIGINT UNSIGNED NOT NULL,
3 | account_id BIGINT UNSIGNED NOT NULL,
4 | PRIMARY KEY (product_id, account_id),
5 | FOREIGN KEY (product_id) REFERENCES Products(product_id),
6 | FOREIGN KEY (account_id) REFERENCES Accounts(account_id)
7 | );
8 |
9 | INSERT INTO Contacts (product_id, account_id)
10 | VALUES (123, 12), (123, 34), (345, 23), (567, 12), (567, 34);
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/soln/group.sql:
--------------------------------------------------------------------------------
1 | -- START:accountsperproduct
2 | SELECT product_id, COUNT(*) AS accounts_per_product
3 | FROM Contacts
4 | GROUP BY product_id;
5 | -- END:accountsperproduct
6 | -- START:productsperaccount
7 | SELECT account_id, COUNT(*) AS products_per_account
8 | FROM Contacts
9 | GROUP BY account_id;
10 | -- END:productsperaccount
11 | -- START:productwithmaxaccounts
12 | SELECT c.product_id, c.contacts_per_product
13 | FROM (
14 | SELECT product_id, COUNT(*) AS accounts_per_product
15 | FROM Contacts
16 | GROUP BY product_id
17 | ) AS c
18 | ORDER BY c.contacts_per_product DESC LIMIT 1
19 | -- END:productwithmaxaccounts
20 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/soln/join.sql:
--------------------------------------------------------------------------------
1 | -- START:productbyaccount
2 | SELECT p.*
3 | FROM Products AS p JOIN Contacts AS c ON (p.product_id = c.product_id)
4 | WHERE c.account_id = 34;
5 | -- END:productbyaccount
6 | -- START:accountbyproduct
7 | SELECT a.*
8 | FROM Accounts AS a JOIN Contacts AS c ON (a.account_id = c.account_id)
9 | WHERE c.product_id = 123;
10 | -- END:accountbyproduct
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Jaywalking/soln/remove.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Contacts (product_id, account_id) VALUES (456, 34);
2 |
3 | DELETE FROM Contacts WHERE product_id = 456 AND account_id = 34;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/delete-child.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM BugStatus WHERE status = 'BOGUS'; -- ERROR!
2 | DELETE FROM Bugs WHERE status = 'BOGUS';
3 | DELETE FROM BugStatus WHERE status = 'BOGUS'; -- retry succeeds
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/delete.sql:
--------------------------------------------------------------------------------
1 | -- START:select
2 | SELECT bug_id FROM Bugs WHERE reported_by = 1;
3 | -- END:select
4 | -- START:delete
5 | DELETE FROM Accounts WHERE account_id = 1;
6 | -- END:delete
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/find-duplicates.sql:
--------------------------------------------------------------------------------
1 | SELECT bug_id FROM Bugs GROUP BY bug_id HAVING COUNT(*) > 1;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/find-orphans.sql:
--------------------------------------------------------------------------------
1 | SELECT b.bug_id, b.status
2 | FROM Bugs b LEFT OUTER JOIN BugStatus s
3 | ON (b.status = s.status)
4 | WHERE s.status IS NULL;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/insert.sql:
--------------------------------------------------------------------------------
1 | -- START:select
2 | SELECT account_id FROM Accounts WHERE account_id = 1;
3 | -- END:select
4 | -- START:insert
5 | INSERT INTO Bugs (reported_by) VALUES (1);
6 | -- END:insert
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/set-default.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs SET status = DEFAULT WHERE status = 'BANANA';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/anti/update-catch22.sql:
--------------------------------------------------------------------------------
1 | UPDATE BugStatus SET status = 'INVALID' WHERE status = 'BOGUS'; -- ERROR!
2 |
3 | UPDATE Bugs SET status = 'INVALID' WHERE status = 'BOGUS'; -- ERROR!
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/soln/cascade.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | -- . . .
3 | reported_by BIGINT UNSIGNED NOT NULL,
4 | status VARCHAR(20) NOT NULL DEFAULT 'NEW',
5 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id)
6 | ON UPDATE CASCADE
7 | ON DELETE RESTRICT,
8 | FOREIGN KEY (status) REFERENCES BugStatus(status)
9 | ON UPDATE CASCADE
10 | ON DELETE SET DEFAULT
11 | );
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Keyless-Entry/soln/foreign-keys.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | -- . . .
3 | reported_by BIGINT UNSIGNED NOT NULL,
4 | status VARCHAR(20) NOT NULL DEFAULT 'NEW',
5 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id),
6 | FOREIGN KEY (status) REFERENCES BugStatus(status)
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Magic-Beans/anti/crud.php:
--------------------------------------------------------------------------------
1 | assigned_to = $a->account_id;
7 | $this->save();
8 | mail($a->email, "Assigned bug",
9 | "You are now responsible for bug #{$this->bug_id}.");
10 | }
11 | }
12 | $bugsTable = Doctrine_Core::getTable('Bugs');
13 | $bug = $bugsTable->find(1234);
14 | $bug->assigned_to = $user->account_id;
15 | $bug->save();
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Magic-Beans/anti/doctrine.php:
--------------------------------------------------------------------------------
1 | find(1234);
4 |
5 | $bug = new Bugs();
6 | $bug->summary = "Crashes when I save";
7 | $bug->save();
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/alter-table.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs_2010 ADD COLUMN hours NUMERIC(9,2);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/anomaly.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs_2010
2 | SET date_reported = '2009-12-27'
3 | WHERE bug_id = 1234;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/check-constraint.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs_2009 (
2 | -- other columns
3 | date_reported DATE CHECK (EXTRACT(YEAR FROM date_reported) = 2009)
4 | );
5 |
6 | CREATE TABLE Bugs_2010 (
7 | -- other columns
8 | date_reported DATE CHECK (EXTRACT(YEAR FROM date_reported) = 2010)
9 | );
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/create-tables.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs_2008 ( . . . );
2 | CREATE TABLE Bugs_2009 ( . . . );
3 | CREATE TABLE Bugs_2010 ( . . . );
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/data-integrity.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs_2009
2 | WHERE date_reported NOT BETWEEN '2009-01-01' AND '2009-12-31';
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/foreign-key.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | bug_id BIGINT UNSIGNED NOT NULL,
4 | FOREIGN KEY (bug_id) REFERENCES Bugs_????(bug_id)
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/id-generator.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsIdGenerator (bug_id SERIAL PRIMARY KEY);
2 |
3 | INSERT INTO BugsIdGenerator (bug_id) VALUES (DEFAULT);
4 | ROLLBACK;
5 |
6 | INSERT INTO Bugs_2010 (bug_id, . . .)
7 | VALUES (LAST_INSERT_ID(), . . .);
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/insert.sql:
--------------------------------------------------------------------------------
1 | -- START:2010
2 | INSERT INTO Bugs_2010 (..., date_reported, ...) VALUES (..., '2010-06-01', ...);
3 | -- END:2010
4 | -- START:2011
5 | INSERT INTO Bugs_2011 (..., date_reported, ...) VALUES (..., '2011-02-20', ...);
6 | -- END:2011
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/join-union.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Accounts a
2 | JOIN (
3 | SELECT * FROM Bugs_2008
4 | UNION ALL
5 | SELECT * FROM Bugs_2009
6 | UNION ALL
7 | SELECT * FROM Bugs_2010
8 | ) t ON (a.account_id = t.reported_by)
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/multi-column.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE ProjectHistory (
2 | bugs_fixed_2008 INT,
3 | bugs_fixed_2009 INT,
4 | bugs_fixed_2010 INT
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/synchronize.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Bugs_2009 (bug_id, date_reported, ...)
2 | SELECT bug_id, date_reported, ...
3 | FROM Bugs_2010
4 | WHERE bug_id = 1234;
5 |
6 | DELETE FROM Bugs_2010 WHERE bug_id = 1234;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/anti/union.sql:
--------------------------------------------------------------------------------
1 | SELECT b.status, COUNT(*) AS count_per_status FROM (
2 | SELECT * FROM Bugs_2008
3 | UNION
4 | SELECT * FROM Bugs_2009
5 | UNION
6 | SELECT * FROM Bugs_2010 ) AS b
7 | GROUP BY b.status;
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/intro/alter-table.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Customers ADD (revenue2002 NUMBER(9,2));
2 | ALTER TABLE Customers ADD (revenue2003 NUMBER(9,2));
3 | ALTER TABLE Customers ADD (revenue2004 NUMBER(9,2));
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/intro/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Customers (
2 | customer_id NUMBER(9) PRIMARY KEY,
3 | contact_info VARCHAR(255),
4 | business_type VARCHAR(20),
5 | revenue NUMBER(9,2)
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/soln/create-history-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE ProjectHistory (
2 | project_id BIGINT,
3 | year SMALLINT,
4 | bugs_fixed INT,
5 | PRIMARY KEY (project_id, year),
6 | FOREIGN KEY (project_id) REFERENCES Projects(project_id)
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/soln/horiz-partition.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY,
3 | -- other columns
4 | date_reported DATE
5 | ) PARTITION BY HASH ( YEAR(date_reported) )
6 | PARTITIONS 4;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/soln/separate-fixed-length.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY, -- fixed length data type
3 | summary CHAR(80), -- fixed length data type
4 | date_reported DATE, -- fixed length data type
5 | reported_by BIGINT UNSIGNED, -- fixed length data type
6 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id)
7 | );
8 |
9 | CREATE TABLE BugDescriptions (
10 | bug_id BIGINT UNSIGNED PRIMARY KEY,
11 | description VARCHAR(1000), -- variable length data type
12 | resolution VARCHAR(1000) -- variable length data type
13 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
14 | );
15 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Metadata-Tribbles/soln/vert-partition.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE ProductInstallers (
2 | product_id BIGINT UNSIGNED PRIMARY KEY,
3 | installer_image BLOB,
4 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/add-tag-two-step.sql:
--------------------------------------------------------------------------------
1 | -- START:select
2 | SELECT * FROM Bugs WHERE bug_id = 3456;
3 | -- END:select
4 | -- START:update
5 | UPDATE Bugs SET tag2 = 'performance' WHERE bug_id = 3456;
6 | -- END:update
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/add-tag.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs
2 | SET tag1 = CASE
3 | WHEN 'performance' IN (tag2, tag3) THEN tag1
4 | ELSE COALESCE(tag1, 'performance') END,
5 | tag2 = CASE
6 | WHEN 'performance' IN (tag1, tag3) THEN tag2
7 | ELSE COALESCE(tag2, 'performance') END,
8 | tag3 = CASE
9 | WHEN 'performance' IN (tag1, tag2) THEN tag3
10 | ELSE COALESCE(tag3, 'performance') END
11 | WHERE bug_id = 3456;
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/alter-table.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs ADD COLUMN tag4 VARCHAR(20);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY,
3 | description VARCHAR(1000),
4 | tag1 VARCHAR(20),
5 | tag2 VARCHAR(20),
6 | tag3 VARCHAR(20)
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/insert-duplicate.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Bugs (description, tag1, tag2, tag3)
2 | VALUES ('printing is slow', 'printing', 'performance', 'performance');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/remove-tag.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs
2 | SET tag1 = NULLIF(tag1, 'performance'),
3 | tag2 = NULLIF(tag2, 'performance'),
4 | tag3 = NULLIF(tag3, 'performance')
5 | WHERE bug_id = 3456;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/search-four-columns.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs
2 | WHERE tag1 = 'performance'
3 | OR tag2 = 'performance'
4 | OR tag3 = 'performance'
5 | OR tag4 = 'performance'; -- you must add this new term
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/search-two-tags.sql:
--------------------------------------------------------------------------------
1 | -- START:style1
2 | SELECT * FROM Bugs
3 | WHERE (tag1 = 'performance' OR tag2 = 'performance' OR tag3 = 'performance')
4 | AND (tag1 = 'printing' OR tag2 = 'printing' OR tag3 = 'printing');
5 | -- END:style1
6 | -- START:style2
7 | SELECT * FROM Bugs
8 | WHERE 'performance' IN (tag1, tag2, tag3)
9 | AND 'printing' IN (tag1, tag2, tag3);
10 | -- END:style2
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs
2 | WHERE tag1 = 'performance'
3 | OR tag2 = 'performance'
4 | OR tag3 = 'performance';
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/anti/update.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs SET tag2 = 'performance' WHERE bug_id = 3456;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/soln/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Tags (
2 | bug_id BIGINT UNSIGNED NOT NULL
3 | tag VARCHAR(20),
4 | PRIMARY KEY (bug_id, tag),
5 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
6 | );
7 |
8 | INSERT INTO Tags (bug_id, tag)
9 | VALUES (1234, 'crash'), (3456, 'printing'), (3456, 'performance');
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/soln/insert-delete.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Tags (bug_id, tag) VALUES (1234, 'save');
2 |
3 | DELETE FROM Tags WHERE bug_id = 1234 AND tag = 'crash';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/soln/search-two-tags.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs
2 | JOIN Tags AS t1 USING (bug_id)
3 | JOIN Tags AS t2 USING (bug_id)
4 | WHERE t1.tag = 'printing' AND t2.tag = 'performance';
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Multi-Column/soln/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs JOIN Tags USING (bug_id)
2 | WHERE tag = 'performance';
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Neat-Freak/anti/lowest-value.sql:
--------------------------------------------------------------------------------
1 | SELECT b1.bug_id + 1
2 | FROM Bugs b1
3 | LEFT OUTER JOIN Bugs AS b2 ON (b1.bug_id + 1 = b2.bug_id)
4 | WHERE b2.bug_id IS NULL
5 | ORDER BY b1.bug_id LIMIT 1;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Neat-Freak/anti/renumber.sql:
--------------------------------------------------------------------------------
1 | UPDATE Bugs SET bug_id = 3 WHERE bug_id = 4;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Neat-Freak/soln/row_number.sql:
--------------------------------------------------------------------------------
1 | SELECT t1.* FROM
2 | (SELECT a.account_name, b.bug_id, b.summary,
3 | ROW_NUMBER() OVER (ORDER BY a.account_name, b.date_reported) AS rn
4 | FROM Accounts a JOIN Bugs b ON (a.account_id = b.reported_by)) AS t1
5 | WHERE t1.rn BETWEEN 51 AND 100;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Neat-Freak/soln/uniqueidentifier-sql2005.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id UNIQUEIDENTIFIER DEFAULT NEWID(),
3 | -- . . .
4 | );
5 |
6 | INSERT INTO Bugs (bug_id, summary)
7 | VALUES (DEFAULT, 'crashes when I save');
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/2NF-anti.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsTags (
2 | bug_id BIGINT NOT NULL,
3 | tag VARCHAR(20) NOT NULL,
4 | tagger BIGINT NOT NULL,
5 | coiner BIGINT NOT NULL,
6 | PRIMARY KEY (bug_id, tag),
7 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
8 | FOREIGN KEY (tagger) REFERENCES Accounts(account_id),
9 | FOREIGN KEY (coiner) REFERENCES Accounts(account_id)
10 | );
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/2NF-normal.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Tags (
2 | tag VARCHAR(20) PRIMARY KEY,
3 | coiner BIGINT NOT NULL,
4 | FOREIGN KEY (coiner) REFERENCES Accounts(account_id)
5 | );
6 |
7 | CREATE TABLE BugsTags (
8 | bug_id BIGINT NOT NULL,
9 | tag VARCHAR(20) NOT NULL,
10 | tagger BIGINT NOT NULL,
11 | PRIMARY KEY (bug_id, tag),
12 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
13 | FOREIGN KEY (tag) REFERENCES Tags(tag),
14 | FOREIGN KEY (tagger) REFERENCES Accounts(account_id)
15 | );
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/3NF-anti.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY
3 | -- . . .
4 | assigned_to BIGINT,
5 | assigned_email VARCHAR(100),
6 | FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id)
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/4NF-anti.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsAccounts (
2 | bug_id BIGINT NOT NULL,
3 | reported_by BIGINT,
4 | assigned_to BIGINT,
5 | verified_by BIGINT,
6 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
7 | FOREIGN KEY (reported_by) REFERENCES Accounts(account_id),
8 | FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id),
9 | FOREIGN KEY (verified_by) REFERENCES Accounts(account_id)
10 | );
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/5NF-anti.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsAssigned (
2 | bug_id BIGINT NOT NULL,
3 | assigned_to BIGINT NOT NULL,
4 | product_id BIGINT NOT NULL,
5 | PRIMARY KEY (bug_id, assigned_to),
6 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
7 | FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id),
8 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
9 | );
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Normalization/5NF-normal.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsAssigned (
2 | bug_id BIGINT NOT NULL,
3 | assigned_to BIGINT NOT NULL,
4 | PRIMARY KEY (bug_id, assigned_to),
5 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
6 | FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id)
7 | );
8 | CREATE TABLE EngineerProducts (
9 | account_id BIGINT NOT NULL,
10 | product_id BIGINT NOT NULL,
11 | PRIMARY KEY (account_id, product_id),
12 | FOREIGN KEY (account_id) REFERENCES Accounts(account_id),
13 | FOREIGN KEY (product_id) REFERENCES Products(product_id)
14 | );
15 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/anti/auth-lumping.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Accounts
2 | WHERE account_name = 'bill' AND password = 'opensesame';
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/anti/auth-plaintext.sql:
--------------------------------------------------------------------------------
1 | SELECT CASE WHEN password = 'opensesame' THEN 1 ELSE 0 END
2 | AS password_matches
3 | FROM Accounts
4 | WHERE account_id = 123;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/anti/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Accounts (
2 | account_id SERIAL PRIMARY KEY,
3 | account_name VARCHAR(20) NOT NULL,
4 | email VARCHAR(100) NOT NULL,
5 | password VARCHAR(30) NOT NULL
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/anti/insert-plaintext.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Accounts (account_id, account_name, email, password)
2 | VALUES (123, 'billkarwin', 'bill@example.com', 'xyzzy');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/anti/select-plaintext.sql:
--------------------------------------------------------------------------------
1 | SELECT account_name, email, password
2 | FROM Accounts
3 | WHERE account_id = 123;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/auth-hash.sql:
--------------------------------------------------------------------------------
1 | SELECT CASE WHEN password_hash = SHA2('xyzzy') THEN 1 ELSE 0 END
2 | AS password_matches
3 | FROM Accounts
4 | WHERE account_id = 123;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/auth-salt.php:
--------------------------------------------------------------------------------
1 | query(
5 | "SELECT salt
6 | FROM Accounts
7 | WHERE account_name = 'bill'");
8 |
9 | $row = $stmt->fetch();
10 | $salt = $row[0];
11 |
12 | $hash = hash('sha256', $password . $salt);
13 |
14 | $stmt = $pdo->query("
15 | SELECT (password_hash = '$hash') AS password_matches;
16 | FROM Accounts AS a
17 | WHERE a.account_name = 'bill'");
18 |
19 | $row = $stmt->fetch();
20 | if ($row === false) {
21 | // account 'bill' does not exist
22 | } else {
23 | $password_matches = $row[0];
24 | if (!$password_matches) {
25 | // password given was incorrect
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Accounts (
2 | account_id SERIAL PRIMARY KEY,
3 | account_name VARCHAR(20),
4 | email VARCHAR(100) NOT NULL,
5 | password_hash CHAR(64) NOT NULL
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/dictionary-attack.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE DictionaryHashes (
2 | password VARCHAR(100),
3 | password_hash CHAR(64)
4 | );
5 |
6 | SELECT a.account_name, h.password
7 | FROM Accounts AS a JOIN DictionaryHashes AS h
8 | ON a.password_hash = h.password_hash;
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/insert-hash.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Accounts (account_id, account_name, email, password_hash)
2 | VALUES (123, 'billkarwin', 'bill@example.com', SHA2('xyzzy'));
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/reset-request.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE PasswordResetRequest (
2 | token CHAR(32) PRIMARY KEY,
3 | account_id BIGINT UNSIGNED NOT NULL,
4 | expiration TIMESTAMP NOT NULL,
5 | FOREIGN KEY (account_id) REFERENCES Accounts(account_id)
6 | );
7 |
8 | SET @token = MD5('billkarwin' || CURRENT_TIMESTAMP || RAND());
9 |
10 | INSERT INTO PasswordResetRequest (token, account_id, expiration)
11 | VALUES (@token, 123, CURRENT_TIMESTAMP + INTERVAL 1 HOUR);
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Passwords/soln/salt.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Accounts (
2 | account_id SERIAL PRIMARY KEY,
3 | account_name VARCHAR(20),
4 | email VARCHAR(100) NOT NULL,
5 | password_hash CHAR(64) NOT NULL,
6 | salt BINARY(8) NOT NULL
7 | );
8 |
9 | INSERT INTO Accounts (account_id, account_name, email,
10 | password_hash, salt)
11 | VALUES (123, 'billkarwin', 'bill@example.com',
12 | SHA2('xyzzy' || '-0xT!sp9'), '-0xT!sp9');
13 |
14 | SELECT (password_hash = SHA2('xyzzy' || salt)) AS password_matches
15 | FROM Accounts
16 | WHERE account_id = 123;
17 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/create-accounts.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Accounts (
2 | account_id SERIAL PRIMARY KEY
3 | account_name VARCHAR(20),
4 | portrait_image BLOB
5 | );
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/create-screenshots-path.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Screenshots (
2 | bug_id BIGINT UNSIGNED NOT NULL,
3 | image_id BIGINT UNSIGNED NOT NULL,
4 | screenshot_path VARCHAR(100),
5 | caption VARCHAR(100),
6 | PRIMARY KEY (bug_id, image_id),
7 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
8 | );
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/create-screenshots.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Screenshots (
2 | bug_id BIGINT UNSIGNED NOT NULL,
3 | image_id SERIAL NOT NULL,
4 | screenshot_image BLOB,
5 | caption VARCHAR(100),
6 | PRIMARY KEY (bug_id, image_id),
7 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
8 | );
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/delete.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM Screenshots WHERE bug_id = 1234 and image_id = 1;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/file-get.php:
--------------------------------------------------------------------------------
1 | query("SELECT image_path FROM Screenshots
6 | WHERE bug_id = 1234 AND image_id = 1");
7 | $row = $stmt->fetch();
8 | $image_path = $row[0];
9 |
10 | // Read the actual image -- I hope the path is correct!
11 | $image = file_get_contents(DATA_DIRECTORY . $image_path);
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/rollback.php:
--------------------------------------------------------------------------------
1 | query("DELETE FROM Screenshots
4 | WHERE bug_id = 1234 AND image_id =1");
5 |
6 | unlink("images/screenshot1234-1.jpg");
7 |
8 | $pdo->rollback();
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/anti/transaction.php:
--------------------------------------------------------------------------------
1 | query("DELETE FROM Screenshots
4 | WHERE bug_id = 1234 AND image_id =1");
5 |
6 | unlink('images/screenshot1234-1.jpg');
7 |
8 | // Other clients still see the row in the database,
9 | // but not the image file.
10 |
11 | $pdo->commit();
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/soln/binary-content.php:
--------------------------------------------------------------------------------
1 | query("SELECT screenshot_image FROM Screenshots
6 | WHERE bug_id = 1234 AND image_id = 1");
7 | $row = $stmt->fetch();
8 |
9 | print $row[0];
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/soln/create-screenshots.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Screenshots (
2 | bug_id BIGINT UNSIGNED NOT NULL,
3 | image_id BIGINT UNSIGNED NOT NULL,
4 | screenshot_image BLOB,
5 | caption VARCHAR(100),
6 | PRIMARY KEY (bug_id, image_id),
7 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
8 | );
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/soln/dumpfile.sql:
--------------------------------------------------------------------------------
1 | SELECT screenshot_image
2 | INTO DUMPFILE 'images/screenshot1234-1.jpg'
3 | FROM Screenshots
4 | WHERE bug_id = 1234 AND image_id =1;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Phantom-Files/soln/load-file.sql:
--------------------------------------------------------------------------------
1 | UPDATE Screenshots
2 | SET screenshot_image = LOAD_FILE('images/screenshot1234-1.jpg')
3 | WHERE bug_id = 1234 AND image_id = 1;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/anti/addresses.sql:
--------------------------------------------------------------------------------
1 | -- START:table
2 | CREATE TABLE Addresses (
3 | address_id SERIAL PRIMARY KEY,
4 | parent VARCHAR(20), -- "Users" or "Orders"
5 | parent_id BIGINT UNSIGNED NOT NULL,
6 | address TEXT
7 | );
8 | -- END:table
9 | -- START:weeds
10 | CREATE TABLE Addresses (
11 | address_id SERIAL PRIMARY KEY,
12 | parent VARCHAR(20), -- "Users" or "Orders"
13 | parent_id BIGINT UNSIGNED NOT NULL,
14 | users_usage VARCHAR(20), -- "billing" or "shipping"
15 | orders_usage VARCHAR(20), -- "billing" or "shipping"
16 | address TEXT
17 | );
18 | -- END:weeds
19 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/anti/comments.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | issue_type VARCHAR(20), -- "Bugs" or "FeatureRequests"
4 | issue_id BIGINT UNSIGNED NOT NULL,
5 | author BIGINT UNSIGNED NOT NULL,
6 | comment_date DATETIME,
7 | comment TEXT,
8 | FOREIGN KEY (author) REFERENCES Accounts(account_id)
9 | );
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/anti/select.sql:
--------------------------------------------------------------------------------
1 | -- START:issue
2 | SELECT *
3 | FROM Bugs AS b JOIN Comments AS c
4 | ON (b.issue_id = c.issue_id AND c.issue_type = 'Bugs')
5 | WHERE b.issue_id = 1234;
6 | -- END:issue
7 | -- START:comment
8 | SELECT *
9 | FROM Comments AS c
10 | LEFT OUTER JOIN Bugs AS b
11 | ON (b.issue_id = c.issue_id AND c.issue_type = 'Bugs')
12 | LEFT OUTER JOIN FeatureRequests AS f
13 | ON (f.issue_id = c.issue_id AND c.issue_type = 'FeatureRequests');
14 | -- END:comment
15 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/intro/comments.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | bug_id BIGINT UNSIGNED NOT NULL,
4 | author_id BIGINT UNSIGNED NOT NULL,
5 | comment_date DATETIME NOT NULL,
6 | comment TEXT NOT NULL,
7 | FOREIGN KEY (author_id) REFERENCES Accounts(account_id),
8 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
9 | );
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/intro/nonsense.sql:
--------------------------------------------------------------------------------
1 | -- START:constraint
2 | ...
3 | FOREIGN KEY (issue_id)
4 | REFERENCES Bugs(issue_id) OR FeatureRequests(issue_id)
5 | );
6 | -- END:constraint
7 | -- START:join
8 | SELECT c.*, i.summary, i.status
9 | FROM Comments AS c
10 | JOIN c.issue_type AS i USING (issue_id);
11 | -- END:join
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/recog/commentable.rb:
--------------------------------------------------------------------------------
1 | #---
2 | # Excerpted from "SQL Antipatterns",
3 | # published by The Pragmatic Bookshelf.
4 | # Copyrights apply to this code. It may not be used to create training material,
5 | # courses, books, articles, and the like. Contact us if you are in doubt.
6 | # We make no guarantees that this code is fit for any purpose.
7 | # Visit http://www.pragmaticprogrammer.com/titles/bksqla for more book information.
8 | #---
9 | class Comment < ActiveRecord::Base
10 | belongs_to :commentable, :polymorphic => true
11 | end
12 |
13 | class Bug < ActiveRecord::Base
14 | has_many :comments, :as => :commentable
15 | end
16 |
17 | class FeatureRequest < ActiveRecord::Base
18 | has_many :comments, :as => :commentable
19 | end
20 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/reverse-coalesce.sql:
--------------------------------------------------------------------------------
1 | SELECT c.*,
2 | COALESCE(b.issue_id, f.issue_id ) AS issue_id,
3 | COALESCE(b.description, f.description) AS description,
4 | COALESCE(b.reporter, f.reporter ) AS reporter,
5 | COALESCE(b.priority, f.priority ) AS priority,
6 | COALESCE(b.status, f.status ) AS status,
7 | b.severity,
8 | b.version_affected,
9 | f.sponsor
10 |
11 | FROM Comments AS c
12 | LEFT OUTER JOIN (BugsComments JOIN Bugs AS b USING (issue_id))
13 | USING (comment_id)
14 | LEFT OUTER JOIN (FeaturesComments JOIN FeatureRequests AS f USING (issue_id))
15 | USING (comment_id)
16 | WHERE c.comment_id = 9876;
17 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/reverse-join.sql:
--------------------------------------------------------------------------------
1 | -- START:issue
2 | SELECT *
3 | FROM BugsComments AS b
4 | JOIN Comments AS c USING (comment_id)
5 | WHERE b.issue_id = 1234;
6 | -- END:issue
7 | -- START:comment
8 | SELECT *
9 | FROM Comments AS c
10 | LEFT OUTER JOIN (BugsComments JOIN Bugs AS b USING (issue_id))
11 | USING (comment_id)
12 | LEFT OUTER JOIN (FeaturesComments JOIN FeatureRequests AS f USING (issue_id))
13 | USING (comment_id)
14 | WHERE c.comment_id = 9876;
15 | -- END:comment
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/reverse-reference.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsComments (
2 | issue_id BIGINT UNSIGNED NOT NULL,
3 | comment_id BIGINT UNSIGNED NOT NULL,
4 | PRIMARY KEY (issue_id, comment_id),
5 | FOREIGN KEY (issue_id) REFERENCES Bugs(issue_id),
6 | FOREIGN KEY (comment_id) REFERENCES Comments(comment_id)
7 | );
8 |
9 |
10 | CREATE TABLE FeaturesComments (
11 | issue_id BIGINT UNSIGNED NOT NULL,
12 | comment_id BIGINT UNSIGNED NOT NULL,
13 | PRIMARY KEY (issue_id, comment_id),
14 | FOREIGN KEY (issue_id) REFERENCES FeatureRequests(issue_id),
15 | FOREIGN KEY (comment_id) REFERENCES Comments(comment_id)
16 | );
17 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/reverse-union.sql:
--------------------------------------------------------------------------------
1 | SELECT b.issue_id, b.description, b.reporter, b.priority, b.status,
2 | b.severity, b.version_affected,
3 | NULL AS sponsor
4 | FROM Comments AS c
5 | JOIN (BugsComments JOIN Bugs AS b USING (issue_id))
6 | USING (comment_id)
7 | WHERE c.comment_id = 9876;
8 |
9 | UNION
10 | SELECT f.issue_id, f.description, f.reporter, f.priority, f.status,
11 | NULL AS severity, NULL AS version_affected,
12 | f.sponsor
13 | FROM Comments AS c
14 | JOIN (FeaturesComments JOIN FeatureRequests AS f USING (issue_id))
15 | USING (comment_id)
16 | WHERE c.comment_id = 9876;
17 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/reverse-unique.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE BugsComments (
2 | issue_id BIGINT UNSIGNED NOT NULL,
3 | comment_id BIGINT UNSIGNED NOT NULL,
4 | UNIQUE KEY (comment_id),
5 | PRIMARY KEY (issue_id, comment_id),
6 | FOREIGN KEY (issue_id) REFERENCES Bugs(issue_id),
7 | FOREIGN KEY (comment_id) REFERENCES Comments(comment_id)
8 | );
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Polymorphic/soln/super-join.sql:
--------------------------------------------------------------------------------
1 | -- START:comment
2 | SELECT *
3 | FROM Comments AS c
4 | LEFT OUTER JOIN Bugs AS b USING (issue_id)
5 | LEFT OUTER JOIN FeatureRequests AS f USING (issue_id)
6 | WHERE c.comment_id = 9876;
7 | -- END:comment
8 | -- START:issue
9 | SELECT *
10 | FROM Bugs AS b
11 | JOIN Comments AS c USING (issue_id)
12 | WHERE b.issue_id = 1234;
13 | -- END:issue
14 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/anti/indexed-sort.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs ORDER BY date_reported;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/anti/orderby-rand.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs ORDER BY RAND() LIMIT 1;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/limit-offset.php:
--------------------------------------------------------------------------------
1 | query($rand)->fetch(PDO::FETCH_ASSOC);
4 | $sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
5 | $stmt = $pdo->prepare($sql);
6 | $stmt->execute( $offset );
7 | $rand_bug = $stmt->fetch();
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/next-higher.sql:
--------------------------------------------------------------------------------
1 | SELECT b1.*
2 | FROM Bugs AS b1
3 | JOIN (SELECT CEIL(RAND() * (SELECT MAX(bug_id) FROM Bugs)) AS bug_id) AS b2
4 | WHERE b1.bug_id >= b2.bug_id
5 | ORDER BY b1.bug_id
6 | LIMIT 1;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/rand-1-to-max.sql:
--------------------------------------------------------------------------------
1 | SELECT b1.*
2 | FROM Bugs AS b1
3 | JOIN (SELECT CEIL(RAND() * (SELECT MAX(bug_id) FROM Bugs)) AS rand_id) AS b2
4 | ON (b1.bug_id = b2.rand_id);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/rand-key-from-list.php:
--------------------------------------------------------------------------------
1 | query("SELECT bug_id FROM Bugs")->fetchAll();
3 |
4 | $rand = random( count($bug_id_list) );
5 | $rand_bug_id = $bug_id_list[$rand]["bug_id"];
6 |
7 | $stmt = $pdo->prepare("SELECT * FROM Bugs WHERE bug_id = ?");
8 | $stmt->execute( array($rand_bug_id) );
9 | $rand_bug = $stmt->fetch();
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/row_number.php:
--------------------------------------------------------------------------------
1 | query($rand)->fetch(PDO::FETCH_ASSOC);
5 |
6 | $sql = "WITH NumberedBugs AS (
7 | SELECT b.*, ROW_NUMBER() OVER (ORDER BY bug_id) AS RN FROM Bugs b
8 | ) SELECT * FROM NumberedBugs WHERE RN = :offset";
9 | $stmt = $pdo->prepare($sql);
10 | $stmt->execute( $offset );
11 | $rand_bug = $stmt->fetch();
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/sample-oracle.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM (SELECT * FROM Bugs SAMPLE (1)
2 | ORDER BY dbms_random.value) WHERE ROWNUM = 1;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Random/soln/tablesample-sql2005.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs TABLESAMPLE (1 ROWS);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/anti/cumulative.sql:
--------------------------------------------------------------------------------
1 | SELECT SUM( b.hours * a.hourly_rate ) AS project_cost
2 | FROM Bugs AS b
3 | JOIN Accounts AS a ON (b.assigned_to = a.account_id);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/anti/inexact.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Accounts WHERE hourly_rate = 59.95;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/anti/magnify-rate.sql:
--------------------------------------------------------------------------------
1 | SELECT hourly_rate * 1000000000 FROM Accounts WHERE account_id = 123;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/anti/select-rate.sql:
--------------------------------------------------------------------------------
1 | SELECT hourly_rate FROM Accounts WHERE account_id = 123;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/anti/threshold.sql:
--------------------------------------------------------------------------------
1 | -- START:coarse
2 | SELECT * FROM Accounts WHERE ABS(hourly_rate - 59.95) < 0.000001;
3 | -- END:coarse
4 | -- START:fine
5 | SELECT * FROM Accounts WHERE ABS(hourly_rate - 59.95) < 0.0000001;
6 | -- END:fine
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/intro/cost-per-bug.sql:
--------------------------------------------------------------------------------
1 | SELECT b.bug_id, b.hours * a.hourly_rate AS cost_per_bug
2 | FROM Bugs AS b
3 | JOIN Accounts AS a ON (b.assigned_to = a.account_id);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/intro/float-columns.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs ADD COLUMN hours FLOAT;
2 |
3 | ALTER TABLE Accounts ADD COLUMN hourly_rate FLOAT;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/soln/exact.sql:
--------------------------------------------------------------------------------
1 | SELECT hourly_rate FROM Accounts WHERE hourly_rate = 59.95;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/soln/magnify-rate-exact.sql:
--------------------------------------------------------------------------------
1 | SELECT hourly_rate * 1000000000 FROM Accounts WHERE hourly_rate = 59.95;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Rounding-Errors/soln/numeric-columns.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs ADD COLUMN hours NUMERIC(9,2);
2 | ALTER TABLE Accounts ADD COLUMN hourly_rate NUMERIC(9,2);
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/delete.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE bug_id = 1234; DELETE FROM Bugs
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/ohare-escape.php:
--------------------------------------------------------------------------------
1 | quote($_REQUEST["name"]);
3 | $sql = "SELECT * FROM Projects WHERE project_name = $project_name";
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/ohare-escape.sql:
--------------------------------------------------------------------------------
1 | -- START:standard
2 | SELECT * FROM Projects WHERE project_name = 'O''Hare'
3 | -- END:standard
4 | -- START:backslash
5 | SELECT * FROM Projects WHERE project_name = 'O\'Hare'
6 | -- END:backslash
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/ohare.php:
--------------------------------------------------------------------------------
1 | prepare("SELECT * FROM Projects WHERE project_name = ?");
3 | $params = array($_REQUEST["name"]);
4 | $stmt->execute($params);
5 | ?>
6 | prepare("SELECT * FROM Bugs WHERE bug_id IN ( ? )");
8 | $stmt->execute(array("1234,3456,5678"));
9 | ?>
10 | prepare("SELECT * FROM ? WHERE bug_id = 1234");
12 | $stmt->execute(array("Bugs"));
13 | ?>
14 | prepare("SELECT * FROM Bugs ORDER BY ?");
16 | $stmt->execute(array("date_reported"));
17 | ?>
18 | prepare("SELECT * FROM Bugs ORDER BY date_reported ?");
20 | $stmt->execute(array("DESC"));
21 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/parameter.sql:
--------------------------------------------------------------------------------
1 | -- START:list
2 | SELECT * FROM Bugs WHERE bug_id IN ( '1234,3456,5678' )
3 | -- END:list
4 | -- START:table
5 | SELECT * FROM 'Bugs' WHERE bug_id = 1234
6 | -- END:table
7 | -- START:column
8 | SELECT * FROM Bugs ORDER BY 'date_reported';
9 | -- END:column
10 | -- START:keyword
11 | SELECT * FROM Bugs ORDER BY date_reported 'DESC'
12 | -- END:keyword
13 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/procedure.sql:
--------------------------------------------------------------------------------
1 | CREATE PROCEDURE UpdatePassword(input_password VARCHAR(20),
2 | input_userid VARCHAR(20))
3 | BEGIN
4 | SET @sql = CONCAT('UPDATE Accounts
5 | SET password_hash = SHA2(', QUOTE(input_password), ')
6 | WHERE account_id = ', input_userid);
7 | PREPARE stmt FROM @sql;
8 | EXECUTE stmt;
9 | END
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/set-password-escape.php:
--------------------------------------------------------------------------------
1 | quote($_REQUEST["password"]);
3 | $userid = $pdo->quote($_REQUEST["userid"]);
4 | $sql = "UPDATE Accounts SET password_hash = SHA2($password)
5 | WHERE account_id = $userid";
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/set-password-escape.sql:
--------------------------------------------------------------------------------
1 | UPDATE Accounts SET password_hash = SHA2('xyzzy')
2 | WHERE account_id = '123 OR TRUE'
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/anti/set-password.php:
--------------------------------------------------------------------------------
1 | query($sql);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/casting.php:
--------------------------------------------------------------------------------
1 | query($sql);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/filter.php:
--------------------------------------------------------------------------------
1 | query($sql);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/interpolate.php:
--------------------------------------------------------------------------------
1 | quote($_REQUEST["active"]);
3 | $sql = "SELECT * FROM Accounts WHERE is_active = {$quoted_active}";
4 | $stmt = $pdo->query($sql);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/mapping.php:
--------------------------------------------------------------------------------
1 | query($sql);
6 |
7 | $sortorders = array( "status" => "status", "date" => "date_reported" );
8 | $directions = array( "up" => "ASC", "down" => "DESC" );
9 |
10 | $sortorder = "bug_id";
11 | $direction = "ASC";
12 |
13 | if (array_key_exists($_REQUEST["order"], $sortorders)) {
14 | $sortorder = $sortorders[ $_REQUEST["order"] ];
15 | }
16 |
17 | if (array_key_exists($_REQUEST["dir"], $directions)) {
18 | $direction = $directions[ $_REQUEST["dir"] ];
19 | }
20 |
21 | $sql = "SELECT * FROM Bugs ORDER BY {$sortorder} {$direction}";
22 | $stmt = $pdo->query($sql);
23 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/orderby.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs ORDER BY status ASC
2 | SELECT * FROM Bugs ORDER BY date_reported DESC
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/parameter-in.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
4 | $stmt->execute($bug_list);
5 | ?>
6 | prepare($sql);
10 | $stmt->execute($bug_list);
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/parameter.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
4 | $params = array($_REQUEST["password"], $_REQUEST["userid"]);
5 | $stmt->execute($params);
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/parameter.sql:
--------------------------------------------------------------------------------
1 | UPDATE Accounts SET password_hash = SHA2('xyzzy')
2 | WHERE account_id = '123 OR TRUE'
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/SQL-Injection/soln/regexp.php:
--------------------------------------------------------------------------------
1 | query($sql);
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/anti/like-false-match.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE description LIKE '%one%';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/anti/like.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE description LIKE '%crash%';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/anti/regexp-word.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE description REGEXP '[[:<:]]one[[:>:]]';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/anti/regexp.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE description REGEXP 'crash';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/inverted-index/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Keywords (
2 | keyword_id SERIAL PRIMARY KEY,
3 | keyword VARCHAR(40) NOT NULL,
4 | UNIQUE KEY (keyword)
5 | );
6 |
7 | CREATE TABLE BugsKeywords (
8 | keyword_id BIGINT UNSIGNED NOT NULL,
9 | bug_id BIGINT UNSIGNED NOT NULL,
10 | PRIMARY KEY (keyword_id, bug_id),
11 | FOREIGN KEY (keyword_id) REFERENCES Keywords(keyword_id),
12 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id)
13 | );
14 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/inverted-index/trigger.sql:
--------------------------------------------------------------------------------
1 | DELIMITER //
2 | -- START:create
3 | CREATE TRIGGER Bugs_Insert AFTER INSERT ON Bugs
4 | FOR EACH ROW
5 | BEGIN
6 | INSERT INTO BugsKeywords (bug_id, keyword_id)
7 | SELECT NEW.bug_id, k.keyword_id FROM Keywords k
8 | WHERE NEW.description REGEXP CONCAT('[[:<:]]', k.keyword, '[[:>:]]')
9 | OR NEW.summary REGEXP CONCAT('[[:<:]]', k.keyword, '[[:>:]]');
10 | END
11 | -- END:create
12 | //
13 | DELIMITER ;
14 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/lucene/create-index.php:
--------------------------------------------------------------------------------
1 | query("SELECT bug_id, summary, description FROM Bugs");
5 |
6 | while ($row = $stmt->fetch()) {
7 | $doc = new Zend_Search_Lucene_Document();
8 | $doc->addField(Zend_Search_Lucene_Field::UnIndexed("bug_id",
9 | $row["bug_id"]));
10 | $doc->addField(Zend_Search_Lucene_Field::Text("summary",
11 | $row["summary"]));
12 | $doc->addField(Zend_Search_Lucene_Field::Text("description",
13 | $row["description"]));
14 | $index->addDocument($doc);
15 | }
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/lucene/search.php:
--------------------------------------------------------------------------------
1 | find($search_expr);
7 |
8 | $bug_id_list = array("0");
9 | foreach ($matches as $match) {
10 | $bug_id_list[] = intval($match->bug_id);
11 | }
12 | $bug_id_list = join(",", $bug_id_list);
13 |
14 | $stmt = $pdo->query("SELECT * FROM Bugs WHERE bug_id IN ($bug_id_list)");
15 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/microsoft/catalog.sql:
--------------------------------------------------------------------------------
1 | EXEC sp_fulltext_database 'enable'
2 | EXEC sp_fulltext_catalog 'BugsCatalog', 'create'
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/microsoft/create-index.sql:
--------------------------------------------------------------------------------
1 | EXEC sp_fulltext_table 'Bugs', 'create', 'BugsCatalog', 'bug_id'
2 | EXEC sp_fulltext_column 'Bugs', 'summary', 'add', '2057'
3 | EXEC sp_fulltext_column 'Bugs', 'description', 'add', '2057'
4 | EXEC sp_fulltext_table 'Bugs', 'activate'
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/microsoft/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE CONTAINS(summary, '"crash"');
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/microsoft/start.sql:
--------------------------------------------------------------------------------
1 | EXEC sp_fulltext_table 'Bugs', 'start_change_tracking'
2 | EXEC sp_fulltext_table 'Bugs', 'start_background_updateindex'
3 | EXEC sp_fulltext_table 'Bugs', 'start_full'
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/mysql/alter-table.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE Bugs ADD FULLTEXT INDEX bugfts (summary, description);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/mysql/match-boolean.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE MATCH(summary, description)
2 | AGAINST ('+crash -save' IN BOOLEAN MODE);
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/mysql/match.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE MATCH(summary, description) AGAINST ('crash');
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/oracle/create-index.sql:
--------------------------------------------------------------------------------
1 | CREATE INDEX BugsText ON Bugs(summary) INDEXTYPE IS CTXSYS.CONTEXT;
2 |
3 | SELECT * FROM Bugs WHERE CONTAINS(summary, 'crash') > 0;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/oracle/ctxcat-create.sql:
--------------------------------------------------------------------------------
1 | CTX_DDL.CREATE_INDEX_SET('BugsCatalogSet');
2 | CTX_DDL.ADD_INDEX('BugsCatalogSet', 'status');
3 | CTX_DDL.ADD_INDEX('BugsCatalogSet', 'priority');
4 |
5 | CREATE INDEX BugsCatalog ON Bugs(summary) INDEXTYPE IS CTXSYS.CTXCAT
6 | PARAMETERS('BugsCatalogSet');
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/oracle/ctxcat-search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs
2 | WHERE CATSEARCH(summary, '(crash save)', 'status = "NEW"') > 0;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/oracle/ctxxpath.sql:
--------------------------------------------------------------------------------
1 | CREATE INDEX BugTestXml ON Bugs(testoutput) INDEXTYPE IS CTXSYS.CTXXPATH;
2 |
3 | SELECT * FROM Bugs
4 | WHERE testoutput.existsNode('/testsuite/test[@status="fail"]') > 0;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/postgresql/create-index.sql:
--------------------------------------------------------------------------------
1 | CREATE INDEX bugs_ts ON Bugs USING GIN(ts_bugtext);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/postgresql/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Bugs (
2 | bug_id SERIAL PRIMARY KEY,
3 | summary VARCHAR(80),
4 | description TEXT,
5 | ts_bugtext TSVECTOR
6 | -- other columns
7 | );
8 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/postgresql/search.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Bugs WHERE ts_bugtext @@ to_tsquery('crash');
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/postgresql/trigger.sql:
--------------------------------------------------------------------------------
1 | CREATE TRIGGER ts_bugtext BEFORE INSERT OR UPDATE ON Bugs
2 | FOR EACH ROW EXECUTE PROCEDURE
3 | tsvector_update_trigger(ts_bugtext, 'pg_catalog.english', summary, description);
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sphinx/indexer.sh:
--------------------------------------------------------------------------------
1 | #---
2 | # Excerpted from "SQL Antipatterns",
3 | # published by The Pragmatic Bookshelf.
4 | # Copyrights apply to this code. It may not be used to create training material,
5 | # courses, books, articles, and the like. Contact us if you are in doubt.
6 | # We make no guarantees that this code is fit for any purpose.
7 | # Visit http://www.pragmaticprogrammer.com/titles/bksqla for more book information.
8 | #---
9 | indexer -c sphinx.conf bugs
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sphinx/search.sh:
--------------------------------------------------------------------------------
1 | #---
2 | # Excerpted from "SQL Antipatterns",
3 | # published by The Pragmatic Bookshelf.
4 | # Copyrights apply to this code. It may not be used to create training material,
5 | # courses, books, articles, and the like. Contact us if you are in doubt.
6 | # We make no guarantees that this code is fit for any purpose.
7 | # Visit http://www.pragmaticprogrammer.com/titles/bksqla for more book information.
8 | #---
9 | search -b "crash -save"
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sphinx/sphinx.conf:
--------------------------------------------------------------------------------
1 | source bugsrc
2 | {
3 | type = mysql
4 | sql_user = bugsuser
5 | sql_pass = xyzzy
6 | sql_db = bugsdatabase
7 | sql_query = \
8 | SELECT bug_id, status, date_reported, summary, description \
9 | FROM Bugs
10 | sql_attr_timestamp = date_reported
11 | sql_attr_str2ordinal = status
12 | sql_query_info = SELECT * FROM Bugs WHERE bug_id = $id
13 | }
14 |
15 | index bugs
16 | {
17 | source = bugsrc
18 | path = /opt/local/var/db/sphinx/bugs
19 | }
20 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sqlite/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE VIRTUAL TABLE BugsText USING fts3(summary, description);
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sqlite/insert.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO BugsText (docid, summary, description)
2 | SELECT bug_id, summary, description FROM Bugs;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sqlite/makefile.in:
--------------------------------------------------------------------------------
1 | TCC += -DSQLITE_CORE=1
2 | TCC += -DSQLITE_ENABLE_FTS3=1
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sqlite/search-boolean.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM BugsText WHERE BugsText MATCH 'crash -save';
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Search/soln/sqlite/search.sql:
--------------------------------------------------------------------------------
1 | SELECT b.* FROM BugsText t JOIN Bugs b ON (t.docid = b.bug_id)
2 | WHERE BugsText MATCH 'crash';
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/See-No-Evil/anti/no-check.php:
--------------------------------------------------------------------------------
1 | prepare($sql); //(2)
7 | $stmt->execute(array(1, "OPEN")); //(3)
8 | $bug = $stmt->fetch(); //(4)
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/See-No-Evil/anti/white-space.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/See-No-Evil/anti/white-space.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM BugsWHERE bug_id = 1234
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/anti/cartesian-no-group.sql:
--------------------------------------------------------------------------------
1 | SELECT p.product_id, f.bug_id AS fixed, o.bug_id AS open
2 | FROM BugsProducts p
3 | JOIN Bugs f ON (p.bug_id = f.bug_id AND f.status = 'FIXED')
4 | JOIN BugsProducts p2 USING (product_id)
5 | JOIN Bugs o ON (p2.bug_id = o.bug_id AND o.status = 'OPEN')
6 | WHERE p.product_id = 1;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/anti/cartesian.sql:
--------------------------------------------------------------------------------
1 | SELECT p.product_id,
2 | COUNT(f.bug_id) AS count_fixed,
3 | COUNT(o.bug_id) AS count_open
4 | FROM BugsProducts p
5 | LEFT OUTER JOIN (BugsProducts bpf JOIN Bugs f USING (bug_id)) f
6 | ON (p.bug_id = f.bug_id AND f.status = 'FIXED')
7 | LEFT OUTER JOIN (BugsProducts bpo JOIN Bugs o USING (bug_id)) o
8 | ON (p.bug_id = o.bug_id AND o.status = 'OPEN')
9 | WHERE p.product_id = 1
10 | GROUP BY p.product_id;
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/intro/report.sql:
--------------------------------------------------------------------------------
1 | SELECT COUNT(bp.product_id) AS how_many_products,
2 | COUNT(dev.account_id) AS how_many_developers,
3 | COUNT(b.bug_id)/COUNT(dev.account_id) AS avg_bugs_per_developer,
4 | COUNT(cust.account_id) AS how_many_customers
5 | FROM Bugs b JOIN BugsProducts bp ON (b.bug_id = bp.bug_id)
6 | JOIN Accounts dev ON (b.assigned_to = dev.account_id)
7 | JOIN Accounts cust ON (b.reported_by = cust.account_id)
8 | WHERE cust.email NOT LIKE '%@example.com'
9 | GROUP BY bp.product_id;
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/bugs-by-customers.sql:
--------------------------------------------------------------------------------
1 | SELECT COUNT(*) AS how_many_customer_bugs
2 | FROM Bugs b JOIN Accounts cust ON (b.reported_by = cust.account_id)
3 | WHERE b.status = 'FIXED' AND cust.email NOT LIKE '%@example.com';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/bugs-per-developer.sql:
--------------------------------------------------------------------------------
1 | SELECT AVG(bugs_per_developer) AS average_bugs_per_developer
2 | FROM (SELECT dev.account_id, COUNT(*) AS bugs_per_developer
3 | FROM Bugs b JOIN Accounts dev
4 | ON (b.assigned_to = dev.account_id)
5 | WHERE b.status = 'FIXED'
6 | GROUP BY dev.account_id) t;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/count-developers.sql:
--------------------------------------------------------------------------------
1 | SELECT COUNT(DISTINCT assigned_to) AS how_many_developers
2 | FROM Bugs
3 | WHERE status = 'FIXED';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/count-products.sql:
--------------------------------------------------------------------------------
1 | SELECT COUNT(*) AS how_many_products
2 | FROM Products;
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/generate-update.sql:
--------------------------------------------------------------------------------
1 | SELECT CONCAT('UPDATE Inventory '
2 | ' SET last_used = ''', MAX(u.usage_date), '''',
3 | ' WHERE inventory_id = ', u.inventory_id, ';') AS update_statement
4 | FROM ComputerUsage u
5 | GROUP BY u.inventory_id;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/split-query.sql:
--------------------------------------------------------------------------------
1 | SELECT p.product_id, COUNT(f.bug_id) AS count_fixed
2 | FROM BugsProducts p
3 | LEFT OUTER JOIN Bugs f ON (p.bug_id = f.bug_id AND f.status = 'FIXED')
4 | WHERE p.product_id = 1
5 | GROUP BY p.product_id;
6 |
7 | SELECT p.product_id, COUNT(o.bug_id) AS count_open
8 | FROM BugsProducts p
9 | LEFT OUTER JOIN Bugs o ON (p.bug_id = o.bug_id AND o.status = 'OPEN')
10 | WHERE p.product_id = 1
11 | GROUP BY p.product_id;
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Spaghetti-Query/soln/union.sql:
--------------------------------------------------------------------------------
1 | (SELECT p.product_id, f.status, COUNT(f.bug_id) AS bug_count
2 | FROM BugsProducts p
3 | LEFT OUTER JOIN Bugs f ON (p.bug_id = f.bug_id AND f.status = 'FIXED')
4 | WHERE p.product_id = 1
5 | GROUP BY p.product_id, f.status)
6 |
7 | UNION ALL
8 |
9 | (SELECT p.product_id, o.status, COUNT(o.bug_id) AS bug_count
10 | FROM BugsProducts p
11 | LEFT OUTER JOIN Bugs o ON (p.bug_id = o.bug_id AND o.status = 'OPEN')
12 | WHERE p.product_id = 1
13 | GROUP BY p.product_id, o.status)
14 |
15 | ORDER BY bug_count;
16 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/adjacency-list.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | parent_id BIGINT UNSIGNED,
4 | bug_id BIGINT UNSIGNED NOT NULL,
5 | author BIGINT UNSIGNED NOT NULL,
6 | comment_date DATETIME NOT NULL,
7 | comment TEXT NOT NULL,
8 | FOREIGN KEY (parent_id) REFERENCES Comments(comment_id),
9 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
10 | FOREIGN KEY (author) REFERENCES Accounts(account_id)
11 | );
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/all-comments.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Comments WHERE bug_id = 1234;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/ancestors.sql:
--------------------------------------------------------------------------------
1 | SELECT c1.*, c2.*, c3.*, c4.*
2 | FROM Comments c1 -- 1st level
3 | LEFT OUTER JOIN Comments c2
4 | ON c2.parent_id = c1.comment_id -- 2nd level
5 | LEFT OUTER JOIN Comments c3
6 | ON c3.parent_id = c2.comment_id -- 3rd level
7 | LEFT OUTER JOIN Comments c4
8 | ON c4.parent_id = c3.comment_id; -- 4th level
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/delete-non-leaf.sql:
--------------------------------------------------------------------------------
1 | SELECT parent_id FROM Comments WHERE comment_id = 6; -- returns 4
2 | UPDATE Comments SET parent_id = 4 WHERE parent_id = 6;
3 | DELETE FROM Comments WHERE comment_id = 6;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/delete-subtree.sql:
--------------------------------------------------------------------------------
1 | SELECT comment_id FROM Comments WHERE parent_id = 4; -- returns 5 and 6
2 | SELECT comment_id FROM Comments WHERE parent_id = 5; -- returns none
3 | SELECT comment_id FROM Comments WHERE parent_id = 6; -- returns 7
4 | SELECT comment_id FROM Comments WHERE parent_id = 7; -- returns none
5 |
6 | DELETE FROM Comments WHERE comment_id IN ( 7 );
7 | DELETE FROM Comments WHERE comment_id IN ( 5, 6 );
8 | DELETE FROM Comments WHERE comment_id = 4;
9 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/insert.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Comments (bug_id, parent_id, author, comment)
2 | VALUES (1234, 7, 'Kukla', 'Thanks!');
3 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/parent.sql:
--------------------------------------------------------------------------------
1 | SELECT c1.*, c2.*
2 | FROM Comments c1 LEFT OUTER JOIN Comments c2
3 | ON c2.parent_id = c1.comment_id;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/anti/update.sql:
--------------------------------------------------------------------------------
1 | UPDATE Comments SET parent_id = 3 WHERE comment_id = 6;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/intro/parent.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | parent_id BIGINT UNSIGNED,
4 | comment TEXT NOT NULL,
5 | FOREIGN KEY (parent_id) REFERENCES Comments(comment_id)
6 | );
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/legit/connect-by.sql:
--------------------------------------------------------------------------------
1 | SELECT * FROM Comments
2 | START WITH comment_id = 9876
3 | CONNECT BY PRIOR parent_id = comment_id;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/legit/cte.sql:
--------------------------------------------------------------------------------
1 | WITH CommentTree
2 | (comment_id, bug_id, parent_id, author, comment, depth)
3 | AS (
4 | SELECT *, 0 AS depth FROM Comments
5 | WHERE parent_id IS NULL
6 | UNION ALL
7 | SELECT c.*, ct.depth+1 AS depth FROM CommentTree ct
8 | JOIN Comments c ON (ct.comment_id = c.parent_id)
9 | )
10 | SELECT * FROM CommentTree WHERE bug_id = 1234;
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/ancestors.sql:
--------------------------------------------------------------------------------
1 | SELECT c.*
2 | FROM Comments AS c
3 | JOIN TreePaths AS t ON c.comment_id = t.ancestor
4 | WHERE t.descendant = 6;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/child.sql:
--------------------------------------------------------------------------------
1 | SELECT *
2 | FROM TreePaths
3 | WHERE ancestor = 4 AND path_length = 1;
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | bug_id BIGINT UNSIGNED NOT NULL,
4 | author BIGINT UNSIGNED NOT NULL,
5 | comment_date DATETIME NOT NULL,
6 | comment TEXT NOT NULL,
7 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
8 | FOREIGN KEY (author) REFERENCES Accounts(account_id)
9 | );
10 |
11 | CREATE TABLE TreePaths (
12 | ancestor BIGINT UNSIGNED NOT NULL,
13 | descendant BIGINT UNSIGNED NOT NULL,
14 | PRIMARY KEY(ancestor, descendant),
15 | FOREIGN KEY (ancestor) REFERENCES Comments(comment_id),
16 | FOREIGN KEY (descendant) REFERENCES Comments(comment_id)
17 | );
18 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/delete-leaf.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM TreePaths WHERE descendant = 7;
2 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/delete-subtree.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM TreePaths
2 | WHERE descendant IN (SELECT descendant
3 | FROM TreePaths
4 | WHERE ancestor = 4);
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/descendants.sql:
--------------------------------------------------------------------------------
1 | SELECT c.*
2 | FROM Comments AS c
3 | JOIN TreePaths AS t ON c.comment_id = t.descendant
4 | WHERE t.ancestor = 4;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/insert.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO TreePaths (ancestor, descendant)
2 | SELECT t.ancestor, 8
3 | FROM TreePaths AS t
4 | WHERE t.descendant = 5
5 | UNION ALL
6 | SELECT 8, 8;
7 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/closure-table/move-subtree.sql:
--------------------------------------------------------------------------------
1 | -- START:delete
2 | DELETE FROM TreePaths
3 | WHERE descendant IN (SELECT descendant
4 | FROM TreePaths
5 | WHERE ancestor = 6)
6 | AND ancestor IN (SELECT ancestor
7 | FROM TreePaths
8 | WHERE descendant = 6
9 | AND ancestor != descendant);
10 | -- END:delete
11 | -- START:reinsert
12 | INSERT INTO TreePaths (ancestor, descendant)
13 | SELECT supertree.ancestor, subtree.descendant
14 | FROM TreePaths AS supertree
15 | CROSS JOIN TreePaths AS subtree
16 | WHERE supertree.descendant = 3
17 | AND subtree.ancestor = 6;
18 | -- END:reinsert
19 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/ancestors.sql:
--------------------------------------------------------------------------------
1 | SELECT c2.*
2 | FROM Comments AS c1
3 | JOIN Comment AS c2
4 | ON c1.nsleft BETWEEN c2.nsleft AND c2.nsright
5 | WHERE c1.comment_id = 6;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | nsleft INTEGER NOT NULL,
4 | nsright INTEGER NOT NULL,
5 | bug_id BIGINT UNSIGNED NOT NULL,
6 | author BIGINT UNSIGNED NOT NULL,
7 | comment_date DATETIME NOT NULL,
8 | comment TEXT NOT NULL,
9 | FOREIGN KEY (bug_id) REFERENCES Bugs (bug_id),
10 | FOREIGN KEY (author) REFERENCES Accounts(account_id)
11 | );
12 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/depth.sql:
--------------------------------------------------------------------------------
1 | -- Reports depth = 3
2 | SELECT c1.comment_id, COUNT(c2.comment_id) AS depth
3 | FROM Comment AS c1
4 | JOIN Comment AS c2
5 | ON c1.nsleft BETWEEN c2.nsleft AND c2.nsright
6 | WHERE c1.comment_id = 7
7 | GROUP BY c1.comment_id;
8 |
9 | DELETE FROM Comment WHERE comment_id = 6;
10 |
11 | -- Reports depth = 2
12 | SELECT c1.comment_id, COUNT(c2.comment_id) AS depth
13 | FROM Comment AS c1
14 | JOIN Comment AS c2
15 | ON c1.nsleft BETWEEN c2.nsleft AND c2.nsright
16 | WHERE c1.comment_id = 7
17 | GROUP BY c1.comment_id;
18 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/descendants.sql:
--------------------------------------------------------------------------------
1 | SELECT c2.*
2 | FROM Comments AS c1
3 | JOIN Comments as c2
4 | ON c2.nsleft BETWEEN c1.nsleft AND c1.nsright
5 | WHERE c1.comment_id = 4;
6 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/insert.sql:
--------------------------------------------------------------------------------
1 | -- make space for NS values 8 and 9
2 | UPDATE Comment
3 | SET nsleft = CASE WHEN nsleft >= 8 THEN nsleft+2 ELSE nsleft END,
4 | nsright = nsright+2
5 | WHERE nsright >= 7;
6 |
7 | -- create new child of comment #5, occupying NS values 8 and 9
8 | INSERT INTO Comment (nsleft, nsright, author, comment)
9 | VALUES (8, 9, 'Fran', 'Me too!');
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/nested-sets/parent.sql:
--------------------------------------------------------------------------------
1 | SELECT parent.*
2 | FROM Comment AS c
3 | JOIN Comment AS parent
4 | ON c.nsleft BETWEEN parent.nsleft AND parent.nsright
5 | LEFT OUTER JOIN Comment AS in_between
6 | ON c.nsleft BETWEEN in_between.nsleft AND in_between.nsright
7 | AND in_between.nsleft BETWEEN parent.nsleft AND parent.nsright
8 | WHERE c.comment_id = 6
9 | AND in_between.comment_id IS NULL;
10 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/path-enum/ancestors.sql:
--------------------------------------------------------------------------------
1 | SELECT *
2 | FROM Comments AS c
3 | WHERE '1/4/6/7/' LIKE c.path || '%';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/path-enum/count.sql:
--------------------------------------------------------------------------------
1 | SELECT COUNT(*)
2 | FROM Comments AS c
3 | WHERE c.path LIKE '1/4/' || '%'
4 | GROUP BY c.author;
5 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/path-enum/create-table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE Comments (
2 | comment_id SERIAL PRIMARY KEY,
3 | path VARCHAR(1000),
4 | bug_id BIGINT UNSIGNED NOT NULL,
5 | author BIGINT UNSIGNED NOT NULL,
6 | comment_date DATETIME NOT NULL,
7 | comment TEXT NOT NULL,
8 | FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
9 | FOREIGN KEY (author) REFERENCES Accounts(account_id)
10 | );
11 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/path-enum/descendants.sql:
--------------------------------------------------------------------------------
1 | SELECT *
2 | FROM Comments AS c
3 | WHERE c.path LIKE '1/4/' || '%';
4 |
--------------------------------------------------------------------------------
/SQL AntiPatterns/code/Trees/soln/path-enum/insert.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO Comments (author, comment) VALUES ('Ollie', 'Good job!');
2 | UPDATE Comments
3 | SET path = (SELECT path FROM Comments WHERE comment_id = 7)
4 | || LAST_INSERT_ID() || '/'
5 | WHERE comment_id = LAST_INSERT_ID();
6 |
--------------------------------------------------------------------------------
/Test-Driven-Development/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | }
4 |
5 | group 'org.example'
6 | version '1.0-SNAPSHOT'
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | test {
13 | useJUnitPlatform()
14 | }
15 |
16 | dependencies {
17 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
18 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
19 | }
20 |
--------------------------------------------------------------------------------
/Test-Driven-Development/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/Test-Driven-Development/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Test-Driven-Development/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/Test-Driven-Development/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'Test-Driven-Development'
2 |
3 |
--------------------------------------------------------------------------------
/Test-Driven-Development/src/test/java/Hello.java:
--------------------------------------------------------------------------------
1 | import org.junit.jupiter.api.Test;
2 |
3 | public class Hello {
4 |
5 | @Test
6 | void hello() {
7 | System.out.println("Hello World");
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/UML실전에서는이것만쓴다/template.md:
--------------------------------------------------------------------------------
1 | # UML 실전에서는 이것만 쓴다 - JAVA 프로그래머를 위한 UML
2 |
3 | ## {n} chapter 주제
4 |
5 | 해당 글은 Robert C.Martin 'UML 실전에서는 이것만 쓴다' 라는 책을 읽고 학습한 내용을 정리 및 회고하는 글 입니다.
6 |
7 | UML 실전에서는 이것만 쓴다 - JAVA 프로그래머를 위한 UML
8 | 인사이트 출판사
9 | 지은이: Robert C.Martin (Uncle Bob)
10 | 옮긴이: 이용원, 정지호
11 |
12 |
13 |
14 |
15 |
16 | ### 이번 장에서 이야기하고자 하는 것
17 |
18 | ### 나의 해석과 회고
19 |
--------------------------------------------------------------------------------
/Working Effectively with Legacy Code/CH17_내 애플리케이션은 뼈대가 약하다.md:
--------------------------------------------------------------------------------
1 | # CHAPTER 17 내 애플리케이션은 뼈대가 약하다
2 |
3 |
4 |
5 | ## 배경
6 |
7 | 오래된 어플리케이션 일 경우 무질서하게 확장되기 쉽다.
8 |
9 | 개발 팀이 아키텍처를 이해하고 있지 않다면 아키텍처는 계속 퇴보한다. 그 이유는?
10 |
11 | - 시스템이 너무 복잡해서 전체 그림을 이해하는 데 오랜 시간이 걸린다
12 | - 시스템이 너무 복잡해서 전체 그림이 아예 없다
13 | - 전체 그림이 없다 보니 긴급 상황이 끊임없이 발생한다. 그리고 이를 처리하느라 땜질 처방에 급급하게 된다.
14 |
15 |
16 |
17 | 여러 기법을 수행해서 팀원들이 아키텍처에 관한 관심을 유지하는 데 도움이 되고, 아키텍쳐를 유지하기 위해 가장 중요한 것이다. 자주 관심을 기울이지 않는 것은 잊혀지기 쉽다.
18 |
19 |
20 |
21 | ## 시스템의 스토리 텔링
22 |
23 | 2명이 서로 질문한다
24 |
25 | "시스템의 아키턱처는 어떤가요?" 그러면 상대방은 최대 2~3개만의 개념을 갖고 시스템의 아키텍쳐를 설명하려고 노력한다.
26 |
27 | - 팀 차원의 의견 공유를 목적으로 시스템의 스토리를 자주 이야기하도록 격려하자.
28 |
29 |
--------------------------------------------------------------------------------
/Working Effectively with Legacy Code/CH18_테스트 코드가 방해를 한다.md:
--------------------------------------------------------------------------------
1 | # 테스트 코드가 방해를 한다
2 |
3 | 어떻게 하면 테스트 코드가 방해가 될 수 있을까? 프로덕트 코드를 검증하기 위해 테스트 코드를 작성하곤 한다. 하지만 무엇을 테스트할 것인지 모른다면 그다지 도움이 될 수 없다.
4 |
5 |
6 |
7 | 어떤 식으로든 규칙을 정해 작업하지 않으면 테스트 코드의 바다에 빠지게 될 것이다.
8 |
9 |
10 |
11 | ### 클래스 명명 규칙
12 |
13 | - 일반적으로 각 클래스마다 적어도 한 개의 단위 테스트 클래스를 작성한다. 따라서 테스트 대상 클래스의 이름을 바탕으로 단위 테스트 클래스를 만드는 것이 합리적이다.
14 | - 보편적으로 클래스 이름의 접두어나 접미어로서 Test 을 붙이는 것
15 |
16 | ### 테스트 코드의 배치
17 |
18 | - src / test 디렉토리 나누기
--------------------------------------------------------------------------------
/Working Effectively with Legacy Code/CH22-괴물메서드를 변경해야하는데 테스트 코드를 작성하지 못하겠다.md:
--------------------------------------------------------------------------------
1 | # CH22. '괴물 메서드'를 변경해야 하는데 테스트 코드를 작성하지 못하겠다
2 |
3 |
4 |
5 | 괴물 메소드를 만나면 어떻게 테스트 코드를 작성할 수 있을까?
6 |
7 | 그 전에 괴물 메소드는 다음과 같은 형태가 있다.
8 |
9 | - 불릿 메소드
10 |
11 | 들여쓰기가 거의 돼 있지 않은 메소드를 말한다. 단지 글머리 기호(블릿)를 갖는 코드 덩어리의 목록을 연상시키기 위해 이렇게
--------------------------------------------------------------------------------
/YOU-DON'T-KNOW-JS/Type-Grammer/REFEREANCE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [자바스크립트의 스코프와 클로저 : TOAST Meetup ](http://meetup.toast.com/posts/86)
4 |
5 | [함수의 범위(scope)](https://www.zerocho.com/category/JavaScript/post/5740531574288ebc5f2ba97e)
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
--------------------------------------------------------------------------------
/asset/image-20241025073215384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025073215384.png
--------------------------------------------------------------------------------
/asset/image-20241025075102856.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025075102856.png
--------------------------------------------------------------------------------
/asset/image-20241025075216018.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025075216018.png
--------------------------------------------------------------------------------
/asset/image-20241025075553244.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025075553244.png
--------------------------------------------------------------------------------
/asset/image-20241025080510228.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025080510228.png
--------------------------------------------------------------------------------
/asset/image-20241025080520927.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025080520927.png
--------------------------------------------------------------------------------
/asset/image-20241025081144309.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025081144309.png
--------------------------------------------------------------------------------
/asset/image-20241025081233681.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025081233681.png
--------------------------------------------------------------------------------
/asset/image-20241025081505978.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025081505978.png
--------------------------------------------------------------------------------
/asset/image-20241025082538446.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025082538446.png
--------------------------------------------------------------------------------
/asset/image-20241025082627905.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025082627905.png
--------------------------------------------------------------------------------
/asset/image-20241025083659761.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025083659761.png
--------------------------------------------------------------------------------
/asset/image-20241025090159987.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241025090159987.png
--------------------------------------------------------------------------------
/asset/image-20241026000546986.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026000546986.png
--------------------------------------------------------------------------------
/asset/image-20241026000800907.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026000800907.png
--------------------------------------------------------------------------------
/asset/image-20241026001531720.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026001531720.png
--------------------------------------------------------------------------------
/asset/image-20241026001947693.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026001947693.png
--------------------------------------------------------------------------------
/asset/image-20241026004238474.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026004238474.png
--------------------------------------------------------------------------------
/asset/image-20241026004959185.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026004959185.png
--------------------------------------------------------------------------------
/asset/image-20241026092259964.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026092259964.png
--------------------------------------------------------------------------------
/asset/image-20241026092347651.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026092347651.png
--------------------------------------------------------------------------------
/asset/image-20241026092423031.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026092423031.png
--------------------------------------------------------------------------------
/asset/image-20241026092854892.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026092854892.png
--------------------------------------------------------------------------------
/asset/image-20241026093411117.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241026093411117.png
--------------------------------------------------------------------------------
/asset/image-20241028101632477.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028101632477.png
--------------------------------------------------------------------------------
/asset/image-20241028101941532.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028101941532.png
--------------------------------------------------------------------------------
/asset/image-20241028102143396.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028102143396.png
--------------------------------------------------------------------------------
/asset/image-20241028102417340.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028102417340.png
--------------------------------------------------------------------------------
/asset/image-20241028102749892.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028102749892.png
--------------------------------------------------------------------------------
/asset/image-20241028104941671.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028104941671.png
--------------------------------------------------------------------------------
/asset/image-20241028104955121.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028104955121.png
--------------------------------------------------------------------------------
/asset/image-20241028105237157.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028105237157.png
--------------------------------------------------------------------------------
/asset/image-20241028105856732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028105856732.png
--------------------------------------------------------------------------------
/asset/image-20241028105938427.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241028105938427.png
--------------------------------------------------------------------------------
/asset/image-20241029125857965.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241029125857965.png
--------------------------------------------------------------------------------
/asset/image-20241029131052859.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241029131052859.png
--------------------------------------------------------------------------------
/asset/image-20241029134809824.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241029134809824.png
--------------------------------------------------------------------------------
/asset/image-20241029135030924.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241029135030924.png
--------------------------------------------------------------------------------
/asset/image-20241030204302345.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241030204302345.png
--------------------------------------------------------------------------------
/asset/image-20241030205122962.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241030205122962.png
--------------------------------------------------------------------------------
/asset/image-20241030205235355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LenKIM/Book/2c194172500688b9d7fe619278e16dda44445c91/asset/image-20241030205235355.png
--------------------------------------------------------------------------------
/clean-architecture/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | #
4 | # These are explicitly windows files and should use crlf
5 | *.bat text eol=crlf
6 |
7 |
--------------------------------------------------------------------------------
/clean-architecture/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore Gradle project-specific cache directory
2 | .gradle
3 |
4 | # Ignore Gradle build output directory
5 | build
6 |
--------------------------------------------------------------------------------
/clean-architecture/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 | # Zeppelin ignored files
10 | /ZeppelinRemoteNotebooks/
11 |
--------------------------------------------------------------------------------
/clean-architecture/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |