SQL Made Easy A Beginners Guide To Easily Learn SQL b096w2gtdf
SQL Made Easy A Beginners Guide To Easily Learn SQL b096w2gtdf
SQL
Notes for Professionals
100+ pages
of professional hints and tricks
GoalKicker.com
not aliated with ocial SQL group(s) or company(s). All trademarks and
registered trademarks are the property of their respective owners
Contents
About
................................................................................................................................................
1
Chapter 1: Getting started with SQL
................................................................................................................... 2
Section 1.1: Overview
................................................................................................................................................
2
Chapter 2: Identifier
................................................................................................................................................
3
Section 2.1: Unquoted identifiers
..................................................................................................................................
3
Chapter 3: Data Types
...............................................................................................................................................
4
Section 3.1: DECIMAL and NUMERIC
............................................................................................................................
4
Section 3.2: FLOAT and REAL
.......................................................................................................................................
4
Section 3.3: Integers
.................................................................................................................................................
4
Section 3.4: MONEY and SMALLMONEY
...................................................................................................................... 4
Section 3.5: BINARY and VARBINARY
..........................................................................................................................
4
Section 3.6: CHAR and VARCHAR
................................................................................................................................
5
Section 3.7: NCHAR and NVARCHAR
..........................................................................................................................
5
Section 3.8: UNIQUEIDENTIFIER
...................................................................................................................................
5
Chapter 4: NULL
.................................................................................................................................................
6
Section 4.1: Filtering for NULL in queries
..................................................................................................................... 6
Section 4.2: Nullable columns in tables
....................................................................................................................... 6
Section 4.3: Updating fields to NULL
...........................................................................................................................
6
Section 4.4: Inserting rows with NULL fields
............................................................................................................... 7
Chapter 5: Example Databases and Tables
.................................................................................................... 8
Section 5.1: Auto Shop Database
.................................................................................................................................
8
Section 5.2: Library Database
....................................................................................................................................
10
Section 5.3: Countries Table
.......................................................................................................................................
13
Chapter 6: SELECT
................................................................................................................................................
14
Section 6.1: Using the wildcard character to select all columns in a query
.......................................................... 14
Section 6.2: SELECT Using Column Aliases
............................................................................................................... 15
Section 6.3: Select Individual Columns
...................................................................................................................... 18
Section 6.4: Selecting specified number of records
................................................................................................. 19
Section 6.5: Selecting with Condition
.........................................................................................................................
20
Section 6.6: Selecting with CASE
................................................................................................................................
20
Section 6.7: Select columns which are named after reserved keywords
.............................................................. 21
Section 6.8: Selecting with table alias
....................................................................................................................... 21
Section 6.9: Selecting with more than 1 condition
.................................................................................................... 22
Section 6.10: Selecting without Locking the table
.................................................................................................... 23
Section 6.11: Selecting with Aggregate functions
..................................................................................................... 23
Section 6.12: Select with condition of multiple values from column
....................................................................... 24
Section 6.13: Get aggregated result for row groups
................................................................................................ 24
Section 6.14: Selection with sorted Results
................................................................................................................ 25
Section 6.15: Selecting with null
..................................................................................................................................
25
Section 6.16: Select distinct (unique values only)
..................................................................................................... 25
Section 6.17: Select rows from multiple tables
......................................................................................................... 26
Chapter 7: GROUP BY
...............................................................................................................................................
27
About
Please feel free to share this PDF with anyone for free, latest version of this
book can be downloaded from: https://goalkicker.com/SQLBook
This SQL Notes for Professionals book is compiled from Stack Overflow
Documentation, the content is written by the beautiful people at Stack
Overflow. Text content is released under Creative Commons BY-SA, see
credits at the end of this book whom contributed to the various chapters.
Images may be copyright of their respective owners unless otherwise
specified
This is an unofficial free book created for educational purposes and is not
affiliated with official SQL group(s) or company(s) nor Stack Overflow. All
trademarks and registered trademarks are the property of their respective
company owners
1. Data Definition Language (DDL): to create and modify the structure of the
database;
2. Data Manipulation Language (DML): to perform Read, Insert, Update and
Delete operations on the data of the database;
3. Data Control Language (DCL): to control the access of the data stored in
the database.
The core DML operations are Create, Read, Update and Delete (CRUD for
short) which are performed by the statements INSERT, SELECT, UPDATE
and DELETE.
There is also a (recently added) MERGE statement which can perform all 3
write operations (INSERT, UPDATE, DELETE).
Chapter 2: Identifier
This topic is about identifiers, i.e. syntax rules for names of tables, columns,
and other database objects.
Where appropriate, the examples should cover variations used by different
SQL implementations, or identify the SQL implementation of the example.
SELECT CAST ('ABC' AS CHAR(10)) -- 'ABC ' (padded with spaces on the
right) SELECT CAST('ABC' AS VARCHAR(10)) -- 'ABC' (no padding due
to variable character) SELECT
CAST('ABCDEFGHIJKLMNOPQRSTUVWXYZ' AS CHAR(10)) --
'ABCDEFGHIJ' (truncated to 10 characters)
@bad_GUID_string, -- 'E28B3BD9-9174-41A9-8508-
899A78A33540_foobarbaz'
CONVERT(UNIQUEIDENTIFIER, @bad_GUID_string) -- 'E28B3BD9-
9174-41A9-8508-899A78A33540'
Chapter 4: NULL
NULL in SQL, as well as programming in general, means literally "nothing".
In SQL, it is easier to understand as "the absence of any value".
It is important to distinguish it from seemingly empty values, such as the
empty string '' or the number 0, neither of which are actually NULL.
It is also important to be careful not to enclose NULL in quotes, like 'NULL',
which is allowed in columns that accept text, but is not NULL and can cause
errors and incorrect data sets.
UPDATE Employees
SET ManagerId = NULL
WHERE Id = 4
Each Department may have 0 or more Employees Each Employee may have
0 or 1 Manager Each Customer may have 0 or more Cars
Departments Id Name
1 HR
2 Sales
3 Tech
);
INSERT INTO Departments ([Id], [Name])
VALUES
(1, 'HR'),
(2, 'Sales'),
(3, 'Tech')
;
);
Customers
Id FName LName Email PhoneNumber PreferredContact 1 William
Jones william.jones@example.com 3347927472 PHONE 2 David Miller
dmiller@example.net 2137921892 EMAIL 3 Richard Davis
richard0123@example.com NULL EMAIL
);
Cars
Id CustomerId EmployeeId Model Status Total Cost 1 1 2 Ford F-150
READY 230 2 1 2 Ford F-150 READY 200 3 2 1 Ford Mustang WAITING
100 4 3 3 Toyota Prius WORKING 1254
SQL statements to create the table:
);
Authors and Books are known as base tables, since they contain column
definition and data for the actual entities in the relational model.
BooksAuthors is known as the relationship table, since this table defines the
relationship between the Books and Authors table.
);
INSERT INTO Authors
(Name, Country)
VALUES
('J.D. Salinger', 'USA'), ('F. Scott. Fitzgerald', 'USA'), ('Jane Austen', 'UK'),
('Scott Hanselman', 'USA'), ('Jason N. Gaylord', 'USA'), ('Pranav Rastogi',
'India'), ('Todd Miranda', 'USA'),
('Christian Wenz', 'USA')
;
Books
(view table)
Id Title
1 The Catcher in the Rye
2 Nine Stories
3 Franny and Zooey
4 The Great Gatsby
5 Tender id the Night
6 Pride and Prejudice
7 Professional ASP.NET 4.5 in C# and VB
SQL to create the table:
);
BooksAuthors
(view table)
BookId AuthorId
11
21
31
42
52
63
74
75
76
77
78
);
Examples
View all authors (view live example):
SELECT * FROM Authors;
View all book titles (view live example):
SELECT * FROM Books;
View all books and their authors (view live example):
SELECT
ba.AuthorId,
a.Name AuthorName,
ba.BookId,
b.Title BookTitle
FROM BooksAuthors ba
INNER JOIN Authors a ON a.id = ba.authorid INNER JOIN Books b ON
b.id = ba.bookid
In this example, we have a Countries table. A table for countries has many
uses, especially in Financial applications involving currencies and exchange
rates.
Live example: SQL fiddle
Some Market data software applications like Bloomberg and Reuters require
you to give their API either a 2 or 3 character country code along with the
currency code. Hence this example table has both the 2-character ISO code
column and the 3 character ISO3 code columns.
Countries
(view table)
Chapter 6: SELECT
The SELECT statement is at the heart of most SQL queries. It defines what
result set should be returned by the query, and is almost always used in
conjunction with the FROM clause, which defines what part(s) of the
database should be queried.
Departments table:
Id Name
1 Sales
2 Marketing
3 Finance
4 IT
SELECT
Employees.*,
Departments.Name
FROM
Employees
JOIN
Departments
ON Departments.Id = Employees.DeptId
This will return a data set with all fields on the Employee table, followed by
just the Name field in the Departments table:
2. Further excess IO load if the database needs to spool internal results to disk
as part of the processing for a query more complex than SELECT <columns>
FROM <table>.
3. Extra processing (and/or even more IO) if some of the unneeded columns
are:
computed columns in databases that support them
in the case of selecting from a view, columns from a table/view that the query
optimiser could otherwise optimise out
4. The potential for unexpected errors if columns are added to tables and
views later that results ambiguous column names. For example SELECT *
FROM orders JOIN people ON people.id = orders.personid ORDER BY
displayname - if a column column called displayname is added to the orders
table to allow users to give their orders meaningful names for future reference
then the column name will appear twice in the output so the ORDER BY
clause will be ambiguous which may cause errors ("ambiguous column
name" in recent MS SQL Server versions), and if not in this example your
application code might start displaying the order name where the person
name is intended because the new column is the first of that name returned,
and so on.
Column aliases are used mainly to shorten code and make column names
more readable.
SELECT
FName AS "First Name", MName AS "Middle Name", LName AS "Last
Name"
FROM Employees
Different Versions of SQL
You can use single quotes ('), double quotes (") and square brackets ([]) to
create an alias in Microsoft SQL Server.
SELECT
FName AS "First Name", MName AS 'Middle Name', LName AS [Last
Name]
FROM Employees
Both will result in:
First Name Middle Name Last Name James John Smith John James
Johnson Michael Marcus Williams
This statement will return FName and LName columns with a given name (an
alias). This is achieved using the AS operator followed by the alias, or simply
writing alias directly after the column name. This means that the following
query has the same outcome as the above.
SELECT
FName "First Name",
MName "Middle Name",
LName "Last Name"
FROM Employees
First Name Middle Name Last Name James John Smith John James
Johnson Michael Marcus Williams
However, the explicit version (i.e., using the AS operator) is more readable.
If the alias has a single word that is not a reserved word, we can write it
without single quotes, double quotes or brackets:
SELECT
FName AS FirstName, LName AS LastName
FROM Employees
FirstName LastName James Smith
John Johnson
Michael Williams
A further variation available in MS SQL Server amongst others is <alias> =
<column-or-calculation>, for instance:
FROM CustomerDetails
which is equivalent to:
FROM CustomerDetails
Both will result in:
FullName Addr1 Addr2 James Smith 123 AnyStreet TownVille John
Johnson 668 MyRoad Anytown Michael Williams 999 High End Dr
Williamsburgh
SELECT
FName as "SELECT", MName as "FROM", LName as "WHERE"
FROM Employees
Different Versions of SQL
Likewise, you can escape keywords in MSSQL with all different approaches:
SELECT
FName AS "SELECT", MName AS 'FROM', LName AS [WHERE]
FROM Employees
SELECT FROM WHERE James John Smith John James Johnson Michael
Marcus Williams
Also, a column alias may be used any of the final clauses of the same query,
such as an ORDER BY:
SELECT
FName AS FirstName, LName AS LastName
FROM
Employees
ORDER BY
LastName DESC
FROM
Employees
ORDER BY
LastName DESC
To create an alias from these reserved words (SELECT and FROM). This
will cause numerous errors on execution.
FROM Customers
This statement will return the columns PhoneNumber, Email, and
PreferredContact from all rows of the Customers table. Also the columns will
be returned in the sequence in which they appear in the SELECT clause.
The result will be:
If multiple tables are joined together, you can select columns from specific
tables by specifying the table name before the column name: [table_name].
[column_name]
SELECT
Customers.PhoneNumber, Customers.Email,
Customers.PreferredContact, Orders.Id AS OrderId
FROM
Customers
LEFT JOIN
Orders ON Orders.CustomerId = Customers.Id
*AS OrderId means that the Id field of Orders table will be returned as a
column named OrderId. See selecting with column alias for further
information.
To avoid using long table names, you can use table aliases. This mitigates the
pain of writing long table names for each field that you select in the joins. If
you are performing a self join (a join between two instances of the same
table), then you must use table aliases to distinguish your tables. We can
write a table alias like Customers c or Customers AS c. Here c works as an
alias for Customers and we can select let's say Email like this: c.Email.
SELECT
c.PhoneNumber,
c.Email,
c.PreferredContact, o.Id AS OrderId
FROM
Customers c
LEFT JOIN
Orders o ON o.CustomerId = c.Id
The SQL 2008 standard defines the FETCH FIRST clause to limit the
number of records returned.
Results: 10 records.
It is important to note that the TOP in Microsoft SQL operates after the
WHERE clause and will return the specified number of results if they exist
anywhere in the table, while ROWNUM works as part of the WHERE clause
so if other conditions do not exist in the specified number of rows at the
beginning of the table, you will get zero results when there could be others to
be found.
When results need to have some logic applied 'on the fly' one can use CASE
statement to implement it.
SELECT CASE WHEN Col1 < 50 THEN 'under' ELSE 'over' END threshold
FROM TableName
also can be chained
SELECT
CASE WHEN Col1 < 50 THEN 'under'
WHEN Col1 > 50 AND Col1 <100 THEN 'between' ELSE 'over'
END threshold
FROM TableName
one also can have CASE inside another CASE statement
SELECT
CASE WHEN Col1 < 50 THEN 'under'
ELSE
CASE WHEN Col1 > 50 AND Col1 <100 THEN Col1 ELSE 'over' END
END threshold
FROM TableName
SELECT
"ORDER", ID
FROM ORDERS
Note that it makes the column name case-sensitive.
Some DBMSes have proprietary ways of quoting names. For example, SQL
Server uses square brackets for this purpose:
SELECT
[Order], ID
FROM ORDERS
while MySQL (and MariaDB) by default use backticks:
SELECT
`Order`, id
FROM orders
The Employees table is given the alias 'e' directly after the table name. This
helps remove ambiguity in scenarios where multiple tables have the same
field name and you need to be specific as to which table you want to return
data from.
Note that although an alias/range variable must be declared for the dervied
table (otherwise SQL will throw an error), it never makes sense to actually
use it in the query.
SELECT name FROM persons WHERE gender = 'M' AND age > 20;
This will return:
Name John
Bob
using OR keyword
SELECT name FROM persons WHERE gender = 'M' OR age < 20;
This will return:
name Sam
John
Bob
These keywords can be combined to allow for more complex criteria
combinations:
SELECT name
FROM persons
WHERE (gender = 'M' AND age < 20)
Oracle
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM TableName;
DB2
SELECT * FROM TableName WITH UR;
where UR stands for "uncommitted read".
If used on table that has record modifications going on might have
unpredictable results.
If you need to filter the results after the grouping has been done, e.g, to see
only departments whose average income is larger than 1000, you need to use
the HAVING clause:
ContinentCode
OC
EU
AS NA AF
SQLFiddle Demo
SELECT
table1.column1, table1.column2, table2.column1
FROM
table1, table2
Chapter 7: GROUP BY
Results of a SELECT query can be grouped by one or more columns using
the GROUP BY statement: all results with the same value in the grouped
columns are aggregated together. This generates a table of partial results,
instead of one result. GROUP BY can be used in conjunction with
aggregation functions using the HAVING statement to define how non-
grouped columns are aggregated.
It might be easier if you think of GROUP BY as "for each" for the sake of
explanation. The query below:
is saying:
"Give me the sum of MonthlySalary's for each EmpID"
So if your table looked like this:
Result:
Sum wouldn't appear to do anything because the sum of one number is that
number. On the other hand if it looked like this:
Result:
Then it would because there are two EmpID 1's to sum together.
SELECT
a.Id,
a.Name,
COUNT(*) BooksWritten
FROM BooksAuthors ba
INNER JOIN Authors a ON a.id = ba.authorid
GROUP BY
a.Id,
a.Name
HAVING COUNT(*) > 1 -- equals to HAVING BooksWritten > 1
;
Return all books that have more than three authors (live example).
SELECT
b.Id,
b.Title,
COUNT(*) NumberOfAuthors
FROM BooksAuthors ba
INNER JOIN Books b ON b.id = ba.bookid
GROUP BY
b.Id,
b.Title
HAVING COUNT(*) > 3 -- equals to HAVING NumberOfAuthors > 3
;
Name GreatHouseAllegience
Arya Stark
Cercei Lannister
Myrcella Lannister
Yara Greyjoy
Catelyn Stark
Sansa Stark
Without GROUP BY, COUNT will simply return a total number of rows:
SELECT Count(*) Number_of_Westerosians FROM Westerosians
returns...
Number_of_Westerosians 6
But by adding GROUP BY, we can COUNT the users for each value in a
given column, to return the number of people in a given Great House, say:
SELECT GreatHouseAllegience House, Count(*) Number_of_Westerosians
FROM Westerosians
GROUP BY GreatHouseAllegience
returns...
returns...
Description
The SQL standard provides two additional aggregate operators. These use the
polymorphic value "ALL" to denote the set of all values that an attribute can
take. The two operators are:
with data cube that it provides all possible combinations than the argument
attributes of the clause. with roll up that it provides the aggregates obtained
by considering the attributes in order from left to right compared how they
are listed in the argument of the clause.
select Food,Brand,Total_amount
from Table
group by Food,Brand,Total_amount with cube
select Food,Brand,Total_amount
from Table
group by Food,Brand,Total_amount with roll up
You can use a column's number (where the leftmost column is '1') to indicate
which column to base the sort on, instead of describing the column by its
name.
Pro: If you think it's likely you might change column names later, doing so
won't break this code.
Con: This will generally reduce readability of the query (It's instantly clear
what 'ORDER BY Reputation' means, while 'ORDER BY 14' requires some
counting, probably with a finger on the screen.)
This query sorts result by the info in relative column position 3 from select
statement instead of column name Reputation.
Section 8.2: Use ORDER BY with TOP to return the top x rows
based on a column's value
In this example, we can use GROUP BY not only determined the sort of the
rows returned, but also what rows are returned, since we're using TOP to
limit the result set.
Let's say we want to return the top 5 highest reputation users from an
unnamed popular Q&A site.
Without ORDER BY
This query returns the Top 5 rows ordered by the default, which in this case
is "Id", the first column in the table (even though it's not a column shown in
the results).
SELECT TOP 5 DisplayName, Reputation
FROM Users
returns...
DisplayName Reputation Community 1
Geoff Dalgas 12567
Jarrod Dixon 11739
Jeff Atwood 37628
Joel Spolsky 25784
With ORDER BY
SELECT TOP 5 DisplayName, Reputation FROM Users
ORDER BY Reputation desc
returns...
DisplayName Reputation JonSkeet 865023
Remarks
Some versions of SQL (such as MySQL) use a LIMIT clause at the end of a
SELECT, instead of TOP at the beginning, for example:
Name Department
Hasan IT
Yusuf HR
Hillary HR
Joe IT
Merry HR
Ken Accountant
SELECT *
FROM Employee
ORDER BY CASE Department
Name Department
Yusuf HR
HillaryHR
Merry HR
Ken Accountant
HasanIT
Joe IT
And can use relative order of the columns in the select statement .Consider
the same example as above and instead of using alias use the relative order
like for display name it is 1 , for Jd it is 2 and so on
Name Bob
Mary
Query
SELECT
COUNT(Id) AS ItemsCount,
SUM ( CASE
SELECT
COUNT(Id) as ItemsCount,
SUM (
CASE PriceRating
WHEN 'Expensive' THEN 1 ELSE 0
END
) AS ExpensiveItemsCount FROM ItemSales
END AS PriceRating
FROM ItemSales
SELECT
CASE ABS(CHECKSUM(NEWID())) % 4 WHEN 0 THEN 'Dr'
WHEN 1 THEN 'Master'
WHEN 2 THEN 'Mr'
WHEN 3 THEN 'Mrs'
END
may produce a NULL result. That is because at each WHEN NEWID() is
being called again with a new result. Equivalent to:
SELECT
CASE
WHEN ABS(CHECKSUM(NEWID())) % 4 = 0 THEN 'Dr' WHEN
ABS(CHECKSUM(NEWID())) % 4 = 1 THEN 'Master' WHEN
ABS(CHECKSUM(NEWID())) % 4 = 2 THEN 'Mr' WHEN
ABS(CHECKSUM(NEWID())) % 4 = 3 THEN 'Mrs'
END
Therefore it can miss all the WHEN cases and result as NULL.
CASE ItemId
WHEN 1 THEN 1.05
WHEN 2 THEN 1.10
WHEN 3 THEN 1.15
ELSE 1.00
END
SELECT ID
,REGION
,CITY
,DEPARTMENT
,EMPLOYEES_NUMBER
FROM DEPT
ORDER BY
CASE WHEN REGION IS NULL THEN 1 ELSE 0
END,
REGION
ID REGION CITY DEPARTMENT EMPLOYEES_NUMBER
10 Mid-Atlantic Philadelphia RESEARCH 13
14 Mid-Atlantic New York SALES 12
9 Midwest Chicago SALES 8
12 New England Boston MARKETING 9
5 West Los Angeles RESEARCH 11
15 NULL San Francisco MARKETING 12
4 NULL Chicago INNOVATION 11
2 NULL Detroit HUMAN RESOURCES 9
The CASE expression in the query below looks at the Date1 and Date2
columns, checks which column has the lower value, and sorts the records
depending on this value.
Sample data
Id Date1 Date2
1 2017-01-01 2017-01-31
2 2017-01-31 2017-01-03
3 2017-01-31 2017-01-02
4 2017-01-06 2017-01-31
5 2017-01-31 2017-01-05
6 2017-01-04 2017-01-31
Query
END
Results
Id Date1 Date2
1 2017-01-012017-01-31
3 2017-01-31 2017-01-02
2 2017-01-312017-01-03
6 2017-01-042017-01-31
5 2017-01-312017-01-05
4 2017-01-062017-01-31
Explanation
As you see row with Id = 1 is first, that because Date1 have lowest record
from entire table 2017-01-01, row where Id = 3 is second that because Date2
equals to 2017-01-02 that is second lowest value from table and so on.
So we have sorted records from 2017-01-01 to 2017-01-06 ascending and no
care on which one column Date1 or Date2 are those values.
Following statement matches for all records having FName containing string
'on' from Employees Table.
SELECT *
FROM T_Whatever
WHERE SomeField LIKE CONCAT('%', @in_SearchText, '%')
However, (apart from the fact that you shouldn't necessarely use LIKE when
you can use fulltext-search) this creates a problem when somebody inputs
text like "50%" or "a_b".
So (instead of switching to fulltext-search), you can solve that problem using
the LIKE-escape statement:
SELECT *
FROM T_Whatever
WHERE SomeField LIKE CONCAT('%', @in_SearchText, '%') ESCAPE '\'
That means \ will now be treated as ESCAPE character. This means, you can
now just prepend \ to every character in the string you search, and the results
will start to be correct, even when the user enters a special character like % or
_.
e.g.
newString += @"\" + c;
sqlCmd.Parameters.Add("@in_SearchText", newString);
// instead of sqlCmd.Parameters.Add("@in_SearchText", stringToSearch);
Note: The above algorithm is for demonstration purposes only. It will not
work in cases where 1 grapheme consists out of several characters (utf-8).
e.g. string stringToSearch = "Les Mise\u0301rables"; You'll need to do this
for each grapheme, not for each character. You should not use the above
algorithm if you're dealing with Asian/East-Asian/South-Asian languages. Or
rather, if you want correct code to begin with, you should just do that for each
graphemeCluster.
See also
ReverseString, a C# interview-question
Eg: //selects all customers with a City starting with "a", "d", or "l" SELECT *
FROM Customers
WHERE City LIKE '[adl]%';
// selects all customers with a City starting with "a", "d", or "l" SELECT *
FROM Customers
WHERE City LIKE '[a-c]%';
[^charlist] - Matches only a character NOT specified within the brackets
Eg: //selects all customers with a City starting with a character that is not "a",
"p", or "l" SELECT * FROM Customers
WHERE City LIKE '[^apl]%';
or
SELECT * FROM Customers
WHERE City NOT LIKE '[apl]%' and city like '_%';
select *
from products
where id in (1,8,3)
select *
from products
where id = 1
or id = 8
or id = 3
The following examples use the Item Sales and Customers sample databases.
Note: The BETWEEN operator is inclusive.
Using the BETWEEN operator with Numbers:
SELECT * From ItemSales
WHERE Quantity BETWEEN 10 AND 17
This query will return all ItemSales records that have a quantity that is greater
or equal to 10 and less than or equal to 17. The results will look like:
When comparing datetime values instead of dates, you may need to convert
the datetime values into a date values, or add or subtract 24 hours to get the
correct results.
Using the BETWEEN operator with Text Values:
SELECT Id, FName, LName FROM Customers WHERE LName
BETWEEN 'D' AND 'L';
Live example: SQL fiddle
This query will return all customers whose name alphabetically falls between
the letters 'D' and 'L'. In this case, Customer #1 and #3 will be returned.
Customer #2, whose name begins with a 'M' will not be included.
Id FName LName
1 William Jones 3 Richard Davis
This query will return the CustomerId and Number of Cars count of any
customer who has more than one car. In this case, the only customer who has
more than one car is Customer #1.
The results will look like:
CustomerId Number of Cars 1 2
SELECT *
FROM Employees
WHERE ManagerId IS NULL
This statement will return all Employee records where the value of the
ManagerId column is NULL.
The result will be:
Id FName LName PhoneNumber ManagerId DepartmentId 1 James Smith
1234567890 NULL 1
SELECT *
FROM Employees
WHERE ManagerId IS NOT NULL
This statement will return all Employee records where the value of the
ManagerId is notNULL.
The result will be:
Note: The same query will not return results if you change the WHERE
clause to WHERE ManagerId = NULL or WHERE ManagerId <> NULL.
Using a WHERE at the end of your SELECT statement allows you to limit
the returned rows to a condition. In this case, where there is an exact match
using the = sign:
SELECT * FROM Employees WHERE DepartmentId = 1
Will only return the rows where the DepartmentId is equal to 1:
Section 13.5: The WHERE clause only returns rows that match
its criteria
Steam has a games under $10 section of their store page. Somewhere deep in
the heart of their systems, there's probably a query that looks something like:
SELECT *
FROM Items
WHERE Price < 10
AND
SELECT * FROM Employees WHERE DepartmentId = 1 AND ManagerId
=1
Will return:
OR
SELECT * FROM Employees WHERE DepartmentId = 2 OR ManagerId = 2
Will return:
Id FName LName PhoneNumber ManagerId DepartmentId Salary Hire_date
CreatedDate ModifiedDate
3 Michael Williams 1357911131 1 2 600 12-05-2009 12-05-2009 NULL
4 Johnathon Smith 1212121212 2 1 500 24-07-2016 24-07-2016 01-01-2002
SELECT *
FROM Cars
WHERE TotalCost IN (100, 200, 300)
This query will return Car #2 which costs 200 and Car #3 which costs 100.
Note that this is equivalent to using multiple clauses with OR, e.g.:
SELECT *
FROM Cars
WHERE TotalCost = 100 OR TotalCost = 200 OR TotalCost = 300
SELECT *
FROM Employees
WHERE FName LIKE 'John'
This query will only return Employee #1 whose first name matches 'John'
exactly.
SELECT *
FROM Employees
WHERE FName like 'John%'
In this case, the query will return Employee #2 whose name is 'John' as well
as Employee #4 whose name is 'Johnathon'.
select customerId
from orders
where productID in (2,3)
group by customerId
having count(distinct productID) = 2
Return value:
customerId 1
The query selects only records with the productIDs in questions and with the
HAVING clause checks for groups having 2 productIds and not just one.
Another possibility would be
select customerId
from orders
group by customerId
having sum(case when productID = 2 then 1 else 0 end) > 0
and sum(case when productID = 3 then 1 else 0 end) > 0 This query selects
only groups having at least one record with productID 2 and at least one with
productID 3.
SELECT Id,
Col1
FROM (SELECT Id,
Col1,
row_number() over (order by Id) RowNumber
FROM TableName)
WHERE RowNumber <= 20
SQL Server:
SELECT TOP 20 *
FROM dbo.[Sale]
MySQL:
SELECT * FROM TableName LIMIT 20, 20; -- offset, limit
Oracle; SQL Server:
SELECT Id,
Col1
FROM TableName)
WHERE RowNumber BETWEEN 21 AND 40
PostgreSQL; SQLite: SELECT * FROM TableName LIMIT 20 OFFSET 20;
MySQL:
SELECT * FROM TableName LIMIT 20, 42424242424242;
-- skips 20 for take use very large number that is more than rows in table
Oracle:
SELECT Id,
Col1
FROM (SELECT Id,
Col1,
row_number() over (order by Id) RowNumber FROM TableName)
WHERE RowNumber > 20
PostgreSQL:
SELECT * FROM TableName OFFSET 20;
SQLite: SELECT * FROM TableName LIMIT 1 OFFSET 20;
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE
user index test test 5 (null) 1 Using where; Using index
1 SIMPLE data ref fk_user fk_user 5 user.test 1 (null)
on type you see if an index was used. In the column possible_keys you see if
the execution plan can choose from different indexes of if none exists. key
tells you the acutal used index. key_len shows you the size in bytes for one
index item. The lower this value is the more index items fit into the same
memory size an they can be faster processed. rows shows you the expected
number of rows the query needs to scan, the lower the better.
Here you see the column names, followed by the columns type. It shows if
null is allowed in the column and if the column uses an Index. the default
value is also displayed and if the table contains any special behavior like an
auto_increment.
Id FirstName LastName
1 Ozgur Ozturk
2 Youssef Medi
3 Henry Tai
Order Table
Id CustomerId Amount
1 2 123.50
2 3 14.80
Get all customers with a least one order
SELECT * FROM Customer WHERE EXISTS (
SELECT * FROM Order WHERE Order.CustomerId=Customer.Id
)
Result
Id FirstName LastName
2 Youssef Medi
3 Henry Tai
Result
Id FirstName LastName 1 Ozgur Ozturk Purpose
EXISTS, IN and JOIN could sometime be used for the same result, however,
they are not equals :
A table may be joined to itself or to any other table. If information from more
than two tables needs to be accessed, multiple joins can be specified in a
FROM clause.
In the below example, for each Employee in the example database Employees
table, a record is returned containing the employee's first name together with
the corresponding first name of the employee's manager. Since managers are
also employees, the table is joined with itself:
SELECT
e.FName AS "Employee",
m.FName AS "Manager"
FROM
Employees e
JOIN
Employees m
ON e.ManagerId = m.Id
Id FName
1 James
2 John
3 Michael
The first action is to create a Cartesian product of all records in the tables
used in the FROM clause. In this case it's the Employees table twice, so the
intermediate table will look like this (I've removed any fields not used in this
example):
The next action is to only keep the records that meet the JOIN criteria, so
any records where the aliased e table ManagerId equals the aliased m table
Id:
Then, each expression used within the SELECT clause is evaluated to return
this table:
Finally, column names e.FName and m.FName are replaced by their alias
column names, assigned with the AS operator:
Employee Manager John James Michael James Johnathon John
SQL has various join types to specify whether (non-)matching rows are
included in the result: INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER
JOIN, and FULL OUTER JOIN (the INNER and OUTER keywords are
optional). The figure below underlines the differences between these types of
joins: the blue area represents the results returned by the join, and the white
area represents the results that the join will not return.
AB
--13243546
Note that (1,2) are unique to A, (3,4) are common, and (5,6) are unique to B.
Inner Join
An inner join using either of the equivalent queries gives the intersection of
the two tables, i.e. the two rows they have in common:
select * from a INNER JOIN b on a.a = b.b; select a.*,b.* from a,b where a.a
= b.b;
a|b
--+-3 | 3 4 | 4
a|b
--+----1 | null 2 | null 3 | 3 4 | 4
Right outer join
Similarly, a right outer join will give all rows in B, plus any common rows in
A:
select * from a RIGHT OUTER JOIN b on a.a = b.b;
a|b
-----+---3 | 3 4 | 4 null | 5 null | 6
a|b
-----+----1 | null
2 | null
3|3
4|4
null | 6 null | 5
CREATE TABLE B (
Y varchar(255) PRIMARY KEY
);
Inner Join
Combines left and right rows that match.
XY
------ ----
Lisa Lisa
Marco Marco
Phil Phil
XY
----- ----
Amy NULL
John NULL
Lisa Lisa
Marco Marco
Phil Phil
XY
----- ------
Lisa Lisa
Marco Marco
Phil Phil
NULL Tim
NULL Vincent
XY
----- ------
Amy NULL
John NULL
Lisa Lisa
Marco Marco
Phil Phil
NULL Tim
NULL Vincent
X
----
Lisa
Marco
Phil
Y
----
Lisa
Marco
Phil
As you can see, there is no dedicated IN syntax for left vs. right semi join -
we achieve the effect simply by switching the table positions within SQL
text.
Left Anti Semi Join
SELECT * FROM A WHERE X NOT IN
(SELECT Y FROM B);
X
---
Amy
John
Y
------
Tim
Vincent
As you can see, there is no dedicated NOT IN syntax for left vs. right anti
semi join - we achieve the effect simply by switching the table positions
within SQL text.
Cross Join
A Cartesian product of all left with all right rows.
SELECT * FROM A CROSS JOIN B;
XY
----- ------
Amy Lisa
John Lisa
Lisa Lisa
Marco Lisa
Phil Lisa
Amy Marco
John Marco
Lisa Marco
Marco Marco
Phil Marco
Amy Phil
John Phil
Lisa Phil
Marco Phil
Phil Phil
Amy Tim
John Tim
Lisa Tim
Marco Tim
Phil Tim
Amy Vincent John Vincent Lisa Vincent Marco Vincent Phil Vincent
Cross join is equivalent to an inner join with join condition which always
matches, so the following query would have returned the same result:
SELECT * FROM A JOIN B ON 1 = 1;
Self-Join
This simply denotes a table joining with itself. A self-join can be any of the
join types discussed above. For example, this is a an inner self-join:
SELECT * FROM A A1 JOIN A A2 ON LEN(A1.X) < LEN(A2.X);
XX
---- ----Amy John Amy Lisa Amy Marco John Marco Lisa Marco Phil Marco
Amy Phil
Id FName
1 James
2 John
3 Michael
and
Id Name
1 HR
2 Sales
3 Tech
As this is a LEFT OUTER JOIN all records are returned from the LEFT side
of the join (Departments), while any records on the RIGHT side are given a
NULL marker if they do not match the join criteria. In the table below this
will return Tech with NULL
Id Name Id FName
1 HR 1 James
1 HR 2 John
1 HR 3 Michael
It is possible to get accidental cross joins which then return incorrect results,
especially if you have a lot of joins in the query.
If you intended a cross join, then it is not clear from the syntax (write out
CROSS JOIN instead), and someone is likely to change it during
maintenance.
The following example will select employee's first names and the name of the
departments they work for:
Cross join does a Cartesian product of the two members, A Cartesian product
means each row of one table is combined with each row of the second table
in the join. For example, if TABLEA has 20 rows and TABLEB has 20 rows,
the result would be 20*20 = 400 output rows.
This makes it possible to, for example, only join the first matching entry in
another table.
The difference between a normal and a lateral join lies in the fact that you can
use a column that you previously joined in the subquery that you "CROSS
APPLY".
Syntax:
PostgreSQL 9.3+
left | right | inner JOIN LATERAL
SQL-Server:
CROSS | OUTER APPLY
INNER JOIN LATERAL is the same as CROSS APPLY and LEFT JOIN
LATERAL is the same as OUTER APPLY
Example usage (PostgreSQL 9.3+):
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON
MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND
MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID
IS NULL -- 989
SELECT
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
, MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
/* AND
(
(__in_DateFrom <=
T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) AND
(__in_DateTo >=
T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
LIMIT 1
) AS FirstOE
And for SQL-Server
SELECT * FROM T_Contacts
SELECT TOP 1
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
, MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
/* AND
(
(@in_DateFrom <=
T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) AND
(@in_DateTo >=
T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
) AS FirstOE
Note that if you're using soft-deletes, you'll have to check the soft-delete
status again in the WHERE-clause (because FULL JOIN behaves kind-of like
a UNION);
It's easy to overlook this little fact, since you put AP_SoftDeleteStatus = 1 in
the join clause.
Also, if you are doing a FULL JOIN, you'll usually have to allow NULL in
the WHERE-clause; forgetting to allow NULL on a value will have the same
effects as an INNER join, which is something you don't want if you're doing
a FULL JOIN.
Example:
SELECT
T_AccountPlan.AP_UID
,T_AccountPlan.AP_Code
, T_AccountPlan.AP_Lang_EN ,T_BudgetPositions.BUP_Budget
,T_BudgetPositions.BUP_UID ,T_BudgetPositions.BUP_Jahr
FROM T_BudgetPositions
FULL JOIN T_AccountPlan
ON T_AccountPlan.AP_UID = T_BudgetPositions.BUP_AP_UID AND
T_AccountPlan.AP_SoftDeleteStatus = 1
WHERE (1=1)
AND (T_BudgetPositions.BUP_SoftDeleteStatus = 1 OR
T_BudgetPositions.BUP_SoftDeleteStatus IS NULL) AND
(T_AccountPlan.AP_SoftDeleteStatus = 1 OR
T_AccountPlan.AP_SoftDeleteStatus IS NULL)
UNION ALL
SELECT People.Name
FROM People
JOIN MyDescendants ON People.Name = MyDescendants.Parent
)
SELECT * FROM MyDescendants;
Joining a subquery is often used when you want to get aggregate data from a
child/details table and display that along with records from the parent/header
table. For example, you might want to get a count of child records, an
average of some numeric column in child records, or the top or bottom row
based on a date or numeric field. This example uses aliases, which arguable
makes queries easier to read when you have multiple tables involved. Here's
what a fairly typical subquery join looks like. In this case we are retrieving all
rows from the parent table Purchase Orders and retrieving only the first row
for each parent record of the child table PurchaseOrderLineItems.
UPDATE
Employees
SET PhoneNumber =
(SELECT
c.PhoneNumber
FROM
Customers c
WHERE
c.FName = Employees.FName
AND c.LName = Employees.LName)
WHERE Employees.PhoneNumber IS NULL
SQL:2003
Update using MERGE:
MERGE INTO
Employees e
USING
Customers c
ON
e.FName = c.Fname
AND e.LName = c.LName
AND e.PhoneNumber IS NULL
WHEN MATCHED THEN
UPDATE
SET PhoneNumber = c.PhoneNumber
SQL Server
Update using INNER JOIN:
UPDATE
Employees
SET
PhoneNumber = c.PhoneNumber
FROM
Employees e
INNER JOIN Customers c
ON e.FName = c.FName AND e.LName = c.LName
WHERE
PhoneNumber IS NULL
UPDATE Cars
SET TotalCost = TotalCost + 100
WHERE Id = 3 or Id = 4
Update operations can include current values in the updated row. In this
simple example the TotalCost is incremented by 100 for two rows:
The TotalCost of Car #3 is increased from 100 to 200 The TotalCost of Car
#4 is increased from 1254 to 1354
A column's new value may be derived from its previous value or from any
other column's value in the same table or a joined table.
UPDATE
Cars
SET
Status = 'READY'
WHERE
Id = 4
This statement will set the status of the row of 'Cars' with id 4 to "READY".
WHERE clause contains a logical expression which is evaluated for each
row. If a row fulfills the criteria, its value is updated. Otherwise, a row
remains unchanged.
Section 19.4: Updating All Rows
This example uses the Cars Table from the Example Databases.
UPDATE Cars
SET Status = 'READY'
This statement will set the 'status' column of all rows of the 'Cars' table to
"READY" because it does not have a WHERE clause to filter the set of rows.
Sometimes one wants to capture the records that have just been updated.
CREATE TABLE #TempUpdated(ID INT)
Parameter Details
tableName The name of the table
columns
Contains an 'enumeration' of all the columns that the table have. See Create a
New Table for more details.
The CREATE TABLE statement is used create a new table in the database. A
table definition consists of a list of columns, their types, and any integrity
constraints.
Section 21.1: Create Table From Select
A basic Employees table, containing an ID, and the employee's first and last
name along with their phone number can be created using
);
This example is specific to Transact-SQL
CREATE TABLE creates a new table in the database, followed by the table
name, Employees
This is then followed by the list of column names and their properties, such
as the ID
primary key states that all values in this column will have unique values
not null states that this column cannot have null values
Below you could find the table Employees with a reference to the table
Cities.
);
);
Here could you find a database diagram.
The
column CityID of table Employees will reference to the column CityID of
table Cities. Below you could find the syntax to make this.
REFERENCES
Cities(CityID)
Meaning
Name of the column
type of the column
Makes the foreign key (optional)
Makes the reference
to the table Cities column CityID
Important: You couldn't make a reference to a table that not exists in the
database. Be source to make first the table Cities and second the table
Employees. If you do it vise versa, it will throw an error.
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO dbo.Sale(Price, SaleDate, Quantity)
VALUES (5.2, GETDATE(), 1)
INSERT INTO dbo.Sale(Price, SaleDate, Quantity)
VALUES (5.2, 'not a date', 1)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
THROW
ROLLBACK TRANSACTION
END CATCH
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO dbo.Sale(Price, SaleDate, Quantity) VALUES (5.2,
GETDATE(), 1)
INSERT INTO dbo.Sale(Price, SaleDate, Quantity) VALUES (5.2,
GETDATE(), 1)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
THROW
ROLLBACK TRANSACTION
END CATCH
Let's say we want to extract the names of all the managers from our
departments.
Using a UNION we can get all the employees from both HR and Finance
departments, which hold the position of a manager
SELECT
FirstName, LastName
FROM
HR_EMPLOYEES
WHERE
Position = 'manager'
UNION ALL
SELECT
FirstName, LastName
FROM
FINANCE_EMPLOYEES
WHERE
Position = 'manager'
The UNION statement removes duplicate rows from the query results. Since
it is possible to have people having the same Name and position in both
departments we are using UNION ALL, in order not to remove duplicates.
If you want to use an alias for each output column, you can just put them in
the first select statement, as follows:
SELECT
FirstName as 'First Name', LastName as 'Last Name'
FROM
HR_EMPLOYEES
WHERE
Position = 'manager'
UNION ALL
SELECT
FirstName, LastName
FROM
FINANCE_EMPLOYEES WHERE
Position = 'manager'
This simplifies your performance tuning since only simple indexes are
needed to perform these queries optimally. You may even be able to get by
with quite a bit fewer non-clustered indexes improving overall write
performance against the source table as well.
Suppose you still need to filter a table against 2 attributes, but you do not
need to filter duplicate records (either because it doesn't matter or your data
wouldn't produce any duplicates during the union due to your data model
design).
This is especially useful when creating Views that join data that is designed
to be physically partitioned across multiple tables (maybe for performance
reasons, but still wants to roll-up records). Since the data is already split,
having the database engine remove duplicates adds no value and just adds
additional processing time to the queries.
This will add a Primary key to the table Employees on the field ID. Including
more than one column name in the parentheses along with ID will create a
Composite Primary Key. When adding more than one column, the column
names must be separated by commas.
ALTER TABLE EMPLOYEES ADD pk_EmployeeID PRIMARY KEY (ID,
FName)
This example will insert all Employees into the Customers table. Since the
two tables have different fields and you don't want to move all the fields over,
you need to set which fields to insert into and which fields to select. The
correlating field names don't need to be called the same thing, but then need
to be the same data type. This example is assuming that the Id field has an
Identity Specification set and will auto increment.
If you have two tables that have exactly the same field names and just want to
move all the records over you can use:
INSERT INTO Table1
SELECT * FROM Table2
Section 26.2: Insert New Row
This statement will insert a new row into the Customers table. Data will only
be inserted into the columns specified note that no value was provided for the
PhoneNumber column. Note, however, that all columns marked as not null
must be included.
MERGE (often also called UPSERT for "update or insert") allows to insert
new rows or, if a row already exists, to update the existing row. The point is
to perform the whole set of operations atomically (to guarantee that the data
remain consistent), and to prevent communication overhead for multiple SQL
statements in a client/server system.
Section 27.1: MERGE to make Target match Source
ON t.PKID = s.PKID
WHEN MATCHED AND NOT EXISTS (
SELECT s.ColumnA, s.ColumnB, s.ColumnC
INTERSECT
SELECT t.ColumnA, t.ColumnB, s.ColumnC
)
Note: The AND NOT EXISTS portion prevents updating records that haven't
changed. Using the INTERSECT construct allows nullable columns to be
compared without special handling.
Suppose we want to know how many users have the same name. Let us create
table users as follows:
);
Now, we just discovered a new user named Joe and would like to take him
into account. To achieve that, we need to determine whether there is an
existing row with his name, and if so, update it to increment count; on the
other hand, if there is no existing row, we should create it.
);
Now, we just discovered a new user named Joe and would like to take him
into account. To achieve that, we need to determine whether there is an
existing row with his name, and if so, update it to increment count; on the
other hand, if there is no existing row, we should create it.
Apply will be used when when table valued function in the right expression.
First query selects data from Department table and uses CROSS APPLY to
evaluate the Employee table for each record of the Department table. Second
query simply joins the Department table with the Employee table and all the
matching records are produced.
SELECT *
FROM Department D
CROSS APPLY (
SELECT *
FROM Employee E
WHERE E.DepartmentID = D.DepartmentID
)A
GO
SELECT *
FROM Department D
INNER JOIN Employee E
ON D.DepartmentID = E.DepartmentID
If you look at the results they produced, it is the exact same result-set; How
does it differ from a JOIN and how does it help in writing more efficient
queries.
The first query in Script #2 selects data from Department table and uses
OUTER APPLY to evaluate the Employee table for each record of the
Department table. For those rows for which there is not a match in Employee
table, those rows contains NULL values as you can see in case of row 5 and
6. The second query simply uses a LEFT OUTER JOIN between the
Department table and the Employee table. As expected the query returns all
rows from Department table; even for those rows for which there is no match
in the Employee table.
SELECT *
FROM Department D
OUTER APPLY (
SELECT *
FROM Employee E
WHERE E.DepartmentID = D.DepartmentID
)A
GO
SELECT *
FROM Department D
LEFT OUTER JOIN Employee E
ON D.DepartmentID = E.DepartmentID GO
Even though the above two queries return the same information, the
execution plan will be bit different. But cost wise there will be not much
difference.
Now comes the time to see where the APPLY operator is really required. In
Script #3, I am creating a table-valued function which accepts DepartmentID
as its parameter and returns all the employees who belong to this department.
The next query selects data from Department table and uses CROSS APPLY
to join with the function we created. It passes the DepartmentID for each row
from the outer table expression (in our case Department table) and evaluates
the function for each row similar to a correlated subquery. The next query
uses the OUTER APPLY in place of CROSS APPLY and hence unlike
CROSS APPLY which returned only correlated data, the OUTER APPLY
returns non-correlated data as well, placing NULLs into the missing columns.
*
FROM Employee E
WHERE E.DepartmentID = @DeptID
)
GO
SELECT
*
FROM Department D
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
GO
SELECT
*
FROM Department D
OUTER APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
GO
So now if you are wondering, can we use a simple join in place of the above
queries? Then the answer is NO, if you replace CROSS/OUTER APPLY in
the above queries with INNER JOIN/LEFT OUTER JOIN, specify ON
clause (something as 1=1) and run the query, you will get "The multi-part
identifier "D.DepartmentID" could not be bound." error. This is because with
JOINs the execution context of outer query is different from the execution
context of the function (or a derived table), and you can not bind a
value/variable from the outer query to the function as a parameter. Hence the
APPLY operator is required for such queries.
This will delete all rows that match the WHERE criteria.
DELETE FROM Employees
WHERE FName = 'John'
Use this to reset the table to the condition at which it was created. This
deletes all rows and resets values such as auto-increment. It also doesn't log
each individual row deletion.
TRUNCATE TABLE Employees
AND TargetSchema.Target.DataDate =
AggregateSchema.Aggregate.AggDate
This essentially results in INNER JOINs between Source, Target and
Aggregate. The deletion is performed on Source when the same IDs exist in
Target AND date present in Target for those IDs also exists in Aggregate.
Same query may also be written (on MySQL, Oracle, Teradata) as:
DELETE Source
FROM Source, TargetSchema.Target, AggregateSchema.Aggregate WHERE
Source.ID = TargetSchema.Target.ID
AND TargetSchema.Target.DataDate =
AggregateSchema.Aggregate.AggDate
Explicit joins may be mentioned in Delete statements on some RDBMS
implementations (e.g. Oracle, MySQL) but not supported on all platforms
(e.g. Teradata does not support them)
Comparisons can be designed to check mismatch scenarios instead of
matching ones with all syntax styles (observe NOT EXISTS below)
The TRUNCATE statement deletes all data from a table. This is similar to
DELETE with no filter, but, depending on the database software, has certain
restrictions and optimizations.
Delete table is a row based operation this means that each row is deleted.
Truncate table is a data page operation the entire data page is reallocated. If
you have a table with a million rows it will be much faster to truncate the
table than it would be to use a delete table statement.
Note that when truncating table, no foreign keys must be present, otherwise
you will get an error.
Assuming a client moves on to some other software, you'll have to delete his
data in your software. But if you do
DELETE FROM T_Client WHERE CLI_ID = x
Then you'll get a foreign key violation, because you can't delete the client
when he still has rooms.
Now you'd have write code in your application that deletes the client's rooms
before it deletes the client. Assume further that in the future, many more
foreign key dependencies will be added in your database, because your
application's functionality expands. Horrible. For every modification in your
database, you'll have to adapt your application's code in N places. Possibly
you'll have to adapt code in other applications as well (e.g. interfaces to other
systems).
A word of caution:
This means you can't simply delete and re-insert the client table anymore,
because if you do this, it will delete all entries in "T_Room"... (no non-delta
updates anymore)
Revoke from User1 and User2 the permission to perform SELECT and
UPDATE operations on table Employees.
Results
);
This will create the Employees table with 'Id' as its primary key. The primary
key can be used to uniquely identify the rows of a table. Only one primary
key is allowed per table.
A key can also be composed by one or more fields, so called composite key,
with the following syntax:
);
PostgreSQL
);
SQLite
Several types of indexes exist, and can be created on a table. When an index
exists on the columns used in a query's WHERE clause, JOIN clause, or
ORDER BY clause, it can substantially improve query performance.
In this case, the index would be useful for queries asking to sort or select by
all included columns, if the set of conditions is ordered in the same way. That
means that when retrieving the data, it can find the rows to retrieve using the
index, instead of looking through the full table.
For example, the following case would utilize the second index;
SELECT * FROM Cars WHERE EmployeeId = 1 Order by CarId DESC
If the order differs, however, the index does not have the same advantages, as
in the following;
SELECT * FROM Cars WHERE OwnerId = 17 Order by CarId DESC
The index is not as helpful because the database must retrieve the entire
index, across all values of EmployeeId and CarID, in order to find which
items have OwnerId = 17.
(The index may still be used; it may be the case that the query optimizer finds
that retrieving the index and filtering on the OwnerId, then retrieving only the
needed rows is faster than retrieving the full table, especially if the table is
large.)
This deletes the index entirely, and if the index is clustered, will remove any
clustering. It cannot be rebuilt without recreating the index, which can be
slow and computationally expensive. As an alternative, the index can be
disabled:
This will create an unique index for the column Email in the table Customers.
This index, along with speeding up queries like a normal index, will also
force every email address in that column to be unique. If a row is inserted or
updated with a non-unique Email value, the insertion or update will, by
default, fail.
By default rebuilding index is offline operation which locks the table and
prevents DML against it , but many RDBMS allow online rebuilding. Also,
some DB vendors offer alternatives to index rebuilding such as
REORGANIZE (SQLServer) or COALESCE/SHRINK SPACE(Oracle).
Section 37.7: Inserting with a Unique Index
WITH cte AS (
SELECT ProjectID,
SELECT
ROW_NUMBER() OVER(ORDER BY Fname ASC) AS RowNumber,
Fname,
LName
FROM Employees
SELECT
ROW_NUMBER() OVER(PARTITION BY DepartmentId ORDER BY
DepartmentId ASC) AS RowNumber, DepartmentId, Fname, LName
FROM Employees
SELECT
storeName,
COUNT(*) AS total_nr_orders,
COUNT(DISTINCT userId) AS nr_unique_customers,
AVG(orderValue) AS average_order_value,
MIN(orderDate) AS first_order,
MAX(orderDate) AS lastOrder
FROM
orders
GROUP BY
storeName;
FROM
orders;
In (standard ANSI/ISO) SQL, the operator for string concatenation is ||. This
syntax is supported by all major databases except SQL Server:
SELECT 'Hello' || 'World' || '!'; --returns HelloWorld!
Many databases support a CONCAT function to join strings:
SELECT CONCAT('Hello', 'World'); --returns 'HelloWorld'
Some databases support using CONCAT to join more than two strings
(Oracle does not):
SELECT CONCAT('Hello', 'World', '!'); --returns 'HelloWorld!'
In some databases, non-string types must be cast or converted:
SELECT CONCAT('Foo', CAST(42 AS VARCHAR(5)), 'Bar'); --returns
'Foo42Bar'
Some databases (e.g., Oracle) perform implicit lossless conversions. For
example, a CONCAT on a CLOB and NCLOB yields a NCLOB. A
CONCAT on a number and a varchar2 results in a varchar2, etc.:
SELECT CONCAT(CONCAT('Foo', 42), 'Bar') FROM dual; --returns
Foo42Bar
Some databases can use the non-standard + operator (but in most, + works
only for numbers):
SELECT 'Foo' + CAST(42 AS VARCHAR(5)) + 'Bar';
On SQL Server < 2012, where CONCAT is not supported, + is the only way
to join strings.
SQL Server
The LEN doesn't count the trailing space.
SELECT LEN('Hello') -- returns 5
SELECT LEN('Hello '); -- returns 5
The DATALENGTH counts the trailing space.
SELECT DATALENGTH('Hello') -- returns 5
SELECT DATALENGTH('Hello '); -- returns 6
It should be noted though, that DATALENGTH returns the length of the
underlying byte representation of the string, which depends, i.a., on the
charset used to store the string.
DECLARE @str varchar(100) = 'Hello ' --varchar is usually an ASCII string,
occupying 1 byte per char
SELECT DATALENGTH(@str) -- returns 6
value
----Lorem ipsum dolor sit
amet.
Syntax is:
LEFT ( string-expression , integer )
RIGHT ( string-expression , integer )
SELECT LEFT('Hello',2) --return He SELECT RIGHT('Hello',2) --return lo
Oracle SQL doesn't have LEFT and RIGHT functions. They can be emulated
with SUBSTR and LENGTH. SUBSTR ( string-expression, 1, integer )
SUBSTR ( string-expression, length(string-expression)-integer+1, integer)
SELECT
FirstName,
REPLACE (Address, 'South', 'Southern') Address
FROM Employees
ORDER BY FirstName
Result:
FirstName James
John
Michael
Address
Southern New York Southern Boston Southern San Diego
Update Statement :
We can use a replace function to make permanent changes in our table
through following approach.
Update Employees
Set city = (Address, 'South', 'Southern');
A more common approach is to use this in conjunction with a WHERE clause
like this:
Update Employees
Set Address = (Address, 'South', 'Southern') Where Address LIKE 'South%';
Payments Table
select customer,
sum(case when payment_type = 'credit' then amount else 0 end) as credit,
sum(case when payment_type = 'debit' then amount else 0 end) as debit
from payments
group by customer
Result:
select customer,
sum(case when payment_type = 'credit' then 1 else 0 end) as
credit_transaction_count, sum(case when payment_type = 'debit' then 1 else 0
end) as debit_transaction_count
from payments
group by customer
Result:
MySQL
SELECT ColumnA
, GROUP_CONCAT(ColumnB ORDER BY ColumnB SEPARATOR ',') AS
ColumnBs
FROM TableName
GROUP BY ColumnA
ORDER BY ColumnA;
FROM TableName
GROUP BY ColumnA
ORDER BY ColumnA;
SQL Server
SQL Server 2016 and earlier
(CTE included to encourage the DRY principle)
WITH CTE_TableName AS (
SELECT ColumnA, ColumnB
FROM TableName)
SELECT t0.ColumnA
, STUFF((
SELECT ',' + t1.ColumnB
FROM CTE_TableName t1
WHERE t1.ColumnA = t0.ColumnA
ORDER BY t1.ColumnB
FROM TableName
GROUP BY ColumnA
ORDER BY ColumnA;
SQLite
without ordering:
SELECT ColumnA
, GROUP_CONCAT(ColumnB, ',') AS ColumnBs
FROM TableName
GROUP BY ColumnA
ORDER BY ColumnA;
FROM CTE_TableName
GROUP BY ColumnA
ORDER BY ColumnA;
DepartmentId TotalSalary
1 2000
2 500
EXAMPLE TABLE
city_name population year
New York City 8,550,405 2015
New York City ... ...
New York City 8,000,906 2005
To select the average population of the New York City, USA from a table
containing city names, population measurements, and measurement years for
last ten years:
QUERY
Notice how measurement year is absent from the query since population is
being averaged over time.
RESULTS
city_name avg_population
New York City 8,250,754
Note: The AVG() function will convert values to numeric types. This is
especially important to keep in mind when working with dates.
DepartmentId NumEmployees
13
21
You can count over a column/expression with the effect that will not count
the NULL values:
SELECT count(ManagerId) mgr FROM EMPLOYEES;
mgr
3
(There is one null value managerID column)
You can also use DISTINCT inside of another function such as COUNT to
only find the DISTINCT members of the set to perform the operation on.
For example:
Will return different values. The SingleCount will only Count individual
Continents once, while the AllCount will include duplicates.
ContinentCode OC
EU
AS
NA
NA
AF
AF
AllCount: 7 SingleCount: 5
The DATENAME function returns the name or value of a specific part of the
date.
SELECT DATENAME (weekday,'2017-01-14') as Datename Datename
Saturday
You use the GETDATE function to determine the current date and time of
the computer running the current SQL instance. This function doesn't include
the time zone difference.
SELECT GETDATE() as Systemdate Systemdate
2017-01-14 11:11:47.7230728
The DATEDIFF function returns the difference between two dates.
In the syntax, datepart is the parameter that specifies which part of the date
you want to use to calculate difference. The datepart can be year, month,
week, day, hour, minute, second, or millisecond. You then specify the start
date in the startdate parameter and the end date in the enddate parameter for
which you want to find the difference.
43660 7
43661 7
43662 7
USE AdventureWorks2012
GO
SELECT FirstName + ' ' + LastName + ' was hired on ' +
FROM Person.Person AS p
JOIN HumanResources.Employee AS e
ON p.BusinessEntityID = e.BusinessEntityID
GO
In the syntax for the function, you specify the string that must be converted,
the AS keyword, and then the required data type. Optionally, you can also
specify the culture in which the string value should be formatted. If you don't
specify this, the language for the session is used.
If the string value can't be converted to a numeric, date, or time format, it will
result in an error. You'll then need to use CAST or CONVERT for the
conversion.
SELECT PARSE('Monday, 13 August 2012' AS datetime2 USING 'en-US')
AS 'Date in English' Date in English
2012-08-13 00:00:00.0000000
In this example, you use the IIF function to return one of two values. If a
sales person's year-to-date sales are above 200,000, this person will be
eligible for a bonus. Values below 200,000 mean that employees don't qualify
for bonuses.
In the example, the input is a negative number, so the Results pane lists the
result -1.
Another mathematical function is the POWER function. This function
provides the value of an expression raised to a specified power.
In the syntax, the float_expression parameter specifies the expression, and the
y parameter specifies the power to which you want to raise the expression.
The default parameter specifies the value that should be returned when the
expression at offset has a NULL value. If you don't specify a value, a value of
NULL is returned.
The LEAD function provides data on rows after the current row in the row
set. For example, in a SELECT statement, you can compare values in the
current row with values in the following row.
You specify the values that should be compared using a scalar expression.
The offset parameter is the number of rows after the current row that will be
used in the comparison.
You specify the value that should be returned when the expression at offset
has a NULL value using the default parameter. If you don't specify these
parameters, the default of one row is used and a value of NULL is returned.
FROM SalesPerson;
This example uses the LEAD and LAG functions to compare the sales values
for each employee to date with those of the employees listed above and
below, with records ordered based on the BusinessEntityID column.
To find the exact value from the row that matches or exceeds the 0.5
percentile, you pass the percentile as the numeric literal in the
PERCENTILE_DISC function. The Percentile Discreet column in a result set
lists the value of the row at which the cumulative distribution is higher than
the specified percentile.
BusinessEntityID
JobTitle
SickLeaveHours
Cumulative Distribution
Percentile Discreet
56
56
56
56
Percentile Continuous
56
56
56
56
FROM SalesTaxRate;
In this example, the FIRST_VALUE function is used to return the ID of the
state or province with the lowest tax rate. The OVER clause is used to order
the tax rates to obtain the lowest rate.
StateProvinceID Name TaxRate FirstValue 74 Utah State Sales Tax 5.00
74
FROM SalesTerritoryHistory;
This example uses the LAST_VALUE function to return the last value for
each rowset in the ordered values.
AS "Percent Rank",
CUME_DIST() OVER(PARTITION BY JobTitle ORDER BY
SickLeaveHours DESC)
AS "Cumulative Distribution"
FROM Employee;
In this example, you use an ORDER clause to partition – or group – the rows
retrieved by the SELECT statement based on employees' job titles, with the
results in each group sorted based on the numbers of sick leave hours that
employees have used.
BusinessEntityID JobTitle
267 Application Specialist
268 Application Specialist
269 Application Specialist
272 Application Specialist
The PERCENT_RANK function ranks the entries within each group. For
each entry, it returns the percentage of entries in the same group that have
lower values.
The CUME_DIST function is similar, except that it returns the percentage of
values less than or equal to the current value.
id name tag
1 example unique_tag
2 foo simple
42 bar simple
3 baz hello
51 quux world
I'd like to get all those lines and know if a tag is used by other lines
SELECT id, name, tag, COUNT(*) OVER (PARTITION BY tag) > 1 AS
flag FROM items
The result will be:
The LAG() analytical function helps to solve the problem by returning for
each row the value in the preceding row:
SELECT * FROM (
SELECT
t.*,
date amount
2016-03-12 200
2016-03-11 -50
2016-03-14 100
2016-03-15 100
2016-03-10 -250
User_ID Completion_Date
1 2016-07-20
1 2016-07-21
2 2016-07-20
2 2016-07-21
2 2016-07-22
;with CTE as
(SELECT *,
Using n=1, you'll get the one most recent row per user_id:
WITH Numbers(i) AS (
--Starting number/index
SELECT 1
--Top-level UNION ALL operator required for recursion
UNION ALL
--Iteration expression:
SELECT i + 1
--Table expression we first declared used as source for recursion
FROM Numbers
--Clause to define the end of the recursion
WHERE i < 5
)
--Use the generated table expression like a regular table
SELECT i FROM Numbers;
i
1
2
3
4
5
This method can be used with any number interval, as well as other types of
data.
SELECT ManagedByJames.Level + 1,
Employees.ID,
Employees.FName,
Employees.LName
FROM Employees
JOIN ManagedByJames
ON Employees.ManagerID = ManagedByJames.ID
WITH ReadyCars AS (
SELECT *
FROM Cars
WHERE Status = 'READY'
)
SELECT ID, Model, TotalCost
FROM ReadyCars
ORDER BY TotalCost;
ID Model TotalCost
1 Ford F-150 200
2 Ford F-150 230
Equivalent subquery syntax
UNION ALL
JOIN ManagersOfJonathon
ON Employees.ID = ManagersOfJonathon.ManagerID )
SELECT * FROM ManagersOfJonathon;
-- Transition Sequence = Rest & Relax into Day Shift into Night Shift
-- RR (Rest & Relax) = 1
-- DS (Day Shift) = 2
-- NS (Night Shift) = 3
; WITH roster AS (
SELECT @DateFrom AS RosterStart, 1 AS TeamA, 2 AS TeamB, 3 AS
TeamC UNION ALL
SELECT DATEADD(d, @IntervalDays, RosterStart),
CASE TeamA WHEN 1 THEN 2 WHEN 2 THEN 3 WHEN 3 THEN 1 END
AS TeamA, CASE TeamB WHEN 1 THEN 2 WHEN 2 THEN 3 WHEN 3
THEN 1 END AS TeamB, CASE TeamC WHEN 1 THEN 2 WHEN 2
THEN 3 WHEN 3 THEN 1 END AS TeamC FROM roster WHERE
RosterStart < DATEADD(d, @IntervalDays, @DateTo)
)
SELECT RosterStart,
ISNULL(LEAD(RosterStart) OVER (ORDER BY RosterStart), RosterStart +
@IntervalDays) AS
RosterEnd,
CASE TeamA WHEN 1 THEN 'RR' WHEN 2 THEN 'DS' WHEN 3 THEN
'NS' END AS TeamA, CASE TeamB WHEN 1 THEN 'RR' WHEN 2 THEN
'DS' WHEN 3 THEN 'NS' END AS TeamB, CASE TeamC WHEN 1 THEN
'RR' WHEN 2 THEN 'DS' WHEN 3 THEN 'NS' END AS TeamC
FROM roster
Result I.e. For Week 1 TeamA is on R&R, TeamB is on Day Shift and
WITH tbl AS (
SELECT id, name, parent_id
FROM mytable)
, tbl_hierarchy AS (
/* Anchor */
SELECT 1 AS "LEVEL"
--, 1 AS CONNECT_BY_ISROOT
--, 0 AS CONNECT_BY_ISBRANCH
, CASE WHEN t.id IN (SELECT parent_id FROM tbl) THEN 0 ELSE 1
END AS CONNECT_BY_ISLEAF , 0 AS CONNECT_BY_ISCYCLE
, '/' + CAST(t.id AS VARCHAR(MAX)) + '/' AS
SYS_CONNECT_BY_PATH_id , '/' + CAST(t.name AS
VARCHAR(MAX)) + '/' AS SYS_CONNECT_BY_PATH_name , t.id AS
root_id
, t.*
FROM tbl t
WHERE t.parent_id IS NULL -- START WITH parent_id IS NULL UNION
ALL
/* Recursive */
SELECT th."LEVEL" + 1 AS "LEVEL"
--, 0 AS CONNECT_BY_ISROOT
--, CASE WHEN t.id IN (SELECT parent_id FROM tbl) THEN 1 ELSE 0
END AS CONNECT_BY_ISBRANCH
Clauses
CONNECT BY: Specifies the relationship that defines the hierarchy.
START WITH: Specifies the root nodes.
ORDER SIBLINGS BY: Orders results properly.
Parameters
NOCYCLE: Stops processing a branch when a loop is detected. Valid
hierarchies are Directed Acyclic Graphs, and circular references violate this
construct.
Operators
PRIOR: Obtains data from the node's parent.
CONNECT_BY_ROOT: Obtains data from the node's root.
Pseudocolumns
LEVEL: Indicates the node's distance from its root.
CONNECT_BY_ISLEAF: Indicates a node without children.
CONNECT_BY_ISCYCLE: Indicates a node with a circular reference.
Functions
SYS_CONNECT_BY_PATH: Returns a flattened/concatenated
representation of the path to the node from its root.
A materialized view is a view whose results are physically stored and must be
periodically refreshed in order to remain current. They are therefore useful
for storing the results of complex, long-running queries when realtime results
are not required. Materialized views can be created in Oracle and
PostgreSQL. Other database systems offer similar functionality, such as SQL
Server's indexed views or DB2's materialized query tables.
number
-------1
(1 row)
number
-------1
(1 row)
SELECT *
FROM Employees -- this is a comment
WHERE FName = 'John'
/* This query
returns all employees */
SELECT *
FROM Employees
);
Insert values with the following statement:
INSERT INTO Department VALUES ('CS205', 'Computer Science');
The following table will contain the information of the subjects offered by the
Computer science branch:
);
(The data type of the Foreign Key must match the datatype of the referenced
key.)
The Foreign Key constraint on the column Dept_Code allows values only if
they already exist in the referenced table, Department. This means that if you
try to insert the following values:
INSERT INTO Programming_Courses Values ('CS300', 'FDB-DB001',
'Database Systems');
the database will raise a Foreign Key violation error, because CS300 does not
exist in the Department table. But when you try a key value that exists:
INSERT INTO Programming_Courses VALUES ('CS205', 'FDB-DB001',
'Database Systems'); INSERT INTO Programming_Courses VALUES
('CS205', 'DB2-DB002', 'Database Systems II');
then the database allows these values.
A few tips for using Foreign Keys
A Foreign Key must reference a UNIQUE (or PRIMARY) key in the parent
table. Entering a NULL value in a Foreign Key column does not raise an
error. Foreign Key constraints can reference tables within the same database.
Foreign Key constraints can refer to another column in the same table (self-
reference).
UPDATE Orders
SET Order_UID = orders_seq.NEXTVAL
WHERE Customer = 581;
It can also be used for SELECTS
SELECT Order_seq.NEXTVAL FROM dual;
FROM Customers
SELECT *
FROM Employees
WHERE Salary = (SELECT MAX(Salary) FROM Employees)
Section 52.4: Correlated Subqueries
SELECT EmployeeId
FROM Employee AS eOuter
WHERE Salary > (
SELECT AVG(Salary)
FROM Employee eInner
WHERE eInner.DepartmentId = eOuter.DepartmentId
)
Subquery SELECT AVG(Salary) ... is correlated because it refers to
Employee row eOuter from its outer query.
SELECT *
FROM Employees AS e
LEFT JOIN Supervisors AS s ON s.EmployeeID=e.EmployeeID WHERE
s.EmployeeID is NULL
You can use subqueries to define a temporary table and use it in the FROM
clause of an "outer" query.
SELECT * FROM (SELECT city, temp_hi - temp_lo AS temp_var FROM
weather) AS w WHERE temp_var > 20;
The above finds cities from the weather table whose daily temperature
variation is greater than 20. The result is:
END
AS
-- Or
EXEC Northwind.getEmployee @LastName = N'Ackerman', @FirstName =
N'Pilar'; GO
-- Or
EXECUTE Northwind.getEmployee @FirstName = N'Pilar', @LastName =
N'Ackerman';
AS
BEGIN
-- insert audit record to MyAudit table
INSERT INTO MyAudit(MyTableId, User)
(SELECT MyTableId, CURRENT_USER FROM inserted)
END
AS
INSERT INTO BooksRecycleBin SELECT *
FROM deleted;
BEGIN TRANSACTION
INSERT INTO DeletedEmployees(EmployeeID, DateDeleted, User)
(SELECT 123, GetDate(), CURRENT_USER);
DELETE FROM Employees WHERE EmployeeID = 123;
COMMIT TRANSACTION
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO Users(ID, Name, Age)
VALUES(1, 'Bob', 24)
ROLLBACK TRANSACTION
END CATCH
1. Each value is atomic; the value in each field in each row must be a single
value.
2. Each field contains values that are of the same data type.
3. Each field heading has a unique name.
4. Each row in the table must have at least one value that makes it unique
amongst the other records in the table.
5. The order of the rows and columns has no significance.
Rule 1: Each value is atomic. Id, Name, DOB and Manager only contain a
single value.
Rule 2: Id contains only integers, Name contains text (we could add that it's
text of four characters or less), DOB contains dates of a valid type and
Manager contains integers (we could add that corresponds to a Primary Key
field in a managers table).
Rule 3: Id, Name, DOB and Manager are unique heading names within the
table.
Rule 4: The inclusion of the Id field ensures that each record is distinct from
any other record within the table.
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%Institution%'
The result contains a list of matching columns, their tables' names, and other
useful information.
4. WHERE: The WHERE filter is applied to VT3. Only rows for which the is
TRUE are inserted to VT4.
5. GROUP BY: The rows from VT4 are arranged in groups based on the
column list specified in the GROUP BY clause. VT5 is generated.
6. CUBE | ROLLUP: Supergroups (groups of groups) are added to the rows
from VT5, generating VT6.
7. HAVING: The HAVING filter is applied to VT6. Only groups for which
the is TRUE are inserted to VT7.
8. SELECT: The SELECT list is processed, generating VT8.
9. DISTINCT: Duplicate rows are removed from VT8. VT9 is generated.
10. ORDER BY: The rows from VT9 are sorted according to the column list
specified in the ORDER BY clause. A cursor is generated (VC10).
11. TOP: The specified number or percentage of rows is selected from the
beginning of VC10. Table VT11 is generated and returned to the caller.
LIMIT has the same functionality as TOP in some SQL dialects such as
Postgres and Netezza.
Names should describe what is stored in their object. This implies that
column names usually should be singular. Whether table names should use
singular or plural is a heavily discussed question, but in practice, it is more
common to use plural table names.
Adding prefixes or suffixes like tbl or col reduces readability, so avoid them.
However, they are sometimes used to avoid conflicts with SQL keywords,
and often used with triggers and indexes (whose names are usually not
mentioned in queries).
Keywords
SQL keywords are not case sensitive. However, it is common practice to
write them in upper case.
SELECT d.Name,
COUNT(*) AS Employees
FROM Departments AS d
JOIN Employees AS e ON d.ID = e.DepartmentID
WHERE d.Name != 'HR'
HAVING COUNT(*) > 10
ORDER BY COUNT(*) DESC;
Sometimes, everything after the SQL keyword introducing a clause is
indented to the same column:
SELECT d.Name,
COUNT(*) AS Employees
FROM Departments AS d
JOIN Employees AS e ON d.ID = e.DepartmentID
WHERE d.Name != 'HR'
HAVING COUNT(*) > 10
ORDER BY COUNT(*) DESC;
(This can also be done while aligning the SQL keywords right.)
Another common style is to put important keywords on their own lines:
SELECT
d.Name,
COUNT(*) AS Employees
FROM
Departments AS d
JOIN
Employees AS e
ON d.ID = e.DepartmentID
WHERE
d.Name != 'HR'
HAVING
COUNT(*) > 10
ORDER BY
COUNT(*) DESC;
SELECT Model,
EmployeeID
FROM Cars
WHERE CustomerID = 42
AND Status = 'READY';
Using multiple lines makes it harder to embed SQL commands into other
programming languages. However, many languages have a mechanism for
multi-line strings, e.g., @"..." in C#, """...""" in Python, or R"(...)" in C++.
--SELECT * don't
SELECT ID, FName, LName, PhoneNumber -- do
FROM Emplopees;
SELECT d.Name,
e.Fname || e.LName AS EmpName
FROM Departments AS d
LEFT JOIN Employees AS e ON d.ID = e.DepartmentID;
SELECT RecipeID,
Recipes.Name,
COUNT(*) AS NumberOfIngredients
FROM Recipes
LEFT JOIN Ingredients USING (RecipeID);
(This requires that both tables use the same column name.
USING automatically removes the duplicate column from the result, e.g., the
join in this query returns a single RecipeID column.)
Credits
Thank you greatly to all the people from Stack Overflow Documentation who
helped provide this content, more changes can be sent to web@petercv.com
for new content to be published or updated
Özgür Öztürk
3N1GM4
a1ex07
Abe Miessler
Abhilash R Vankayala
aholmes
Aidan
alex9311
Almir Vuk
Alok Singh
Ameya Deshpande
Amir Pourmand رﯾﻤﺎ
دﻧﻤﺮوپ
Amnon
Andrea
Andrea Montanari
Andreas
Andy G
apomene
Ares
Arkh
Arpit Solanki
Arthur D
Arulkumar
ashja99
Athafoud
Ayaz Shah
A_Arnold
Bart Schuijt
Batsu
bhs
bignose
blackbishop
Blag
Bostjan
Branko Dimitrijevic
Brent Oliver
brichins
carlosb
Chris
Christian
Christian Sagmüller
Christos
CL.
Cristian Abelleira
DaImTo
Daniel
Chapters 8 and 17
Chapter 7
Chapter 37
Chapter 7
Chapters 5, 6, 11, 27, 30 and 32
Chapter 6
Chapters 21 and 25
Chapter 21
Chapters 21 and 37
Chapter 6
Chapter 26
Chapter 56
Chapter 6
Chapter 24
Chapter 36
Chapter 2
Chapter 18
Chapter 6
Chapter 21
Chapter 45
Chapter 6
Chapter 41
Chapters 13 and 41
Chapters 11 and 42
Chapter 24
Chapter 11
Chapter 18
Chapter 11
Chapter 41
Chapter 45
Chapter 5
Chapter 25
Chapter 17
Chapters 5, 7 and 13
Chapter 18
Chapter 6
Chapter 54
Chapters 37 and 39
Chapter 6
Chapter 5
Chapter 6
Chapter 6
Chapters 1, 2, 6, 8, 10, 14, 18, 19, 21, 31, 36, 37, 41, 42, 46, 49, 61 and 62
Chapter 30
Chapter 30
Chapter 46
Chapters 18 and 24
Chapter 6
Chapters 10 and 19
Chapter 40
Chapters 18 and 57
Chapters 6, 55, 56 and 58 Chapter 52
Chapter 37
Chapter 6
Chapter 6
Chapter 6
Chapter 46
Chapter 48
Chapter 6
Chapters 21 and 29
Chapter 20
Chapter 6
Chapters 5, 18, 25, 42 and 47 Chapters 5, 6, 19, 36 and 37 Chapters 5 and 18
Chapters 6, 18 and 41
Chapter 7
Chapter 46
Chapter 60
Chapter 1
Chapter 45
Chapter 41
Chapter 9
Chapter 21
Chapter 59
Chapter 11
Chapter 50
Chapter 41
Chapter 11
Chapter 18
Chapter 18
Chapter 6
Chapter 37
Chapter 30
Chapter 42
Chapter 6
Chapters 6, 41 and 42
Chapter 6
Chapter 55
Chapter 6
Chapter 24
Chapter 5
Chapter 41
Chapters 6, 7, 8 and 10
Chapter 37
Chapter 45
Chapter 24
Chapter 24
Joel
John Odom
John Slegers
John Smith
JohnLBevan
Jojodmo
Jon Chan
Jon Ericson
JonH
juergen d
Karthikeyan
Kewin Björk Nielsen KIRAN KUMAR MATAM KjetilNordin
Knickerless
Lankymart
LCIII
Leigh Riffel
Lexi
Lohitha Palagiri
Mark Iannucci
Mark Perera
Mark Stewart
Matas Vaitkevicius Mateusz Piotrowski Matt
Matt S
Mattew Whitt
mauris
Mihai
mithra chintha
MotKohn
Mureinik
mustaccio
Mzzzzzz
Nathan
nazark
Neria Nachum
Nunie123
Oded
Ojen
omini data
onedaywhen
Ozair Kafray
Parado
Paul Bambury
Paulo Freitas
Peter K
Phrancis
Prateek
Preuk
Racil Hilan
raholling
Chapters 29 and 31
Chapters 6, 18, 22, 32 and 56
Chapters 6 and 18
Chapter 51
Chapter 1
Chapter 21
Chapter 13
Chapters 1 and 13
Chapter 6
Chapters 12, 13 and 42
Chapter 28
Chapters 41 and 43
Chapter 21
Chapter 36
Chapter 62
Chapter 6
Chapter 15
Chapter 41
Chapter 25
Chapter 11
Chapters 6 and 18
Chapters 6 and 11
Chapter 43
Chapters 6, 13, 14, 19, 21 and 41
Chapter 41
Chapters 5, 6 and 10
Chapter 6
Chapter 6
Chapter 37
Chapters 6 and 24
Chapters 8 and 25
Chapter 10
Chapters 10, 18 and 45
Chapters 6 and 45
Chapter 5
Chapter 42
Chapter 8
Chapter 41
Chapter 52
Chapter 6
Chapters 6 and 11
Chapters 42 and 44
Chapter 6
Chapter 25
Chapters 8 and 37
Chapter 30
Chapter 37
Chapters 42 and 46
Chapters 1, 3, 4, 8, 11, 13, 18, 19, 29, 38, 41, 46, 49, 52 and 53 Chapters 1, 6
and 21
Chapter 6
Chapter 6
Chapter 18
rajarshig
RamenChef
Reboot
Redithion
Ricardo Pontual
Robert Columbia Ryan
Ryan Rockey
Saroj Sasmal
Shiva
Sibeesh Venu
Simon Foster
Simone
Simulant
SommerEngineering SQLFox
sqluser
Chapter 26
Chapter 41
Chapter 42
Chapter 11
Chapter 22
Chapters 6 and 41 Chapter 37
Chapter 60
Chapters 4 and 6 Chapter 5
Chapter 46
Chapter 25
Chapter 7
Chapter 16
Chapter 6
Chapter 27
Chapter 6
Stanislovas Kalašnikovas Chapter 10
Stefan Steiger
Steven
Stivan
Stu
Timothy
tinlyx
Tot Zam
Uberzen1
Umesh
user1221533
user1336087
user2314737
user5389107
Vikrant
vmaroli
walid
WesleyJohnson William Ledbetter wintersolider
Wolfgang
xenodevil
xQbert
Yehuda Shapira ypercube
Yury Fedorov
Zaga
Zahiro Mor
zedfoxus
Zoyd
zplizzi
ɐlǝx
Алексей Неудачин Рахул Маквана