Download presentation
Presentation is loading. Please wait.
1
There’s a particular style to it…
Thinking in SQL There’s a particular style to it… Rob Hatton
2
SQL is not a complete language
No way to build a user interface No way to read or write to a file Can’t print Doesn’t even know about variables It’s awesome at retrieving data!
3
SQL Server has 2 languages
ANSI SQL Based on Sets TSQL We’ll be talking about ANSI SQL
4
SQL is a different kind of language
Most languages are procedural Like telling a story It’s the reason for TSQL SQL is a declarative language Like painting a picture The complete solution does both It’s a comic book Sets are key to understanding SQL
5
Types Of SQL Statements
Data Definition Language (DDL) Create (Table, View, Proc) Alter (Table, View, Proc) Drop (Table, View, Proc) Data Manipulation Language (DML) Select Insert Delete Update Database definition is stored in a database. DDL manipulates the definition. We’re not going to focus on DDL.
6
Select Syntax SELECT field_list [ FROM set_source ] (includes joins)
[ WHERE search_expression ] (record based) [ GROUP BY group_expression ] [ HAVING aggregate_expression ] [ ORDER BY order_expression [ ASC | DESC ] ] Where clause logic is record based, not set based! ‘Where eyeColor = ‘blue’ and eyeColor = ‘green’ returns no records. ‘Group by’ requires an aggregate function in select list. ‘Having’ only works with group by. Where clause logic is record based, not set based! ‘Where eyeColor = ‘blue’ and eyeColor = ‘green’ returns no records. ‘Group by’ requires an aggregate function in select list. ‘Having’ only works with group by.
7
Aliasing select fis.orderDateKey , max(fis.salesAmount) as maxAmt
from factInternetSales fis group by fis.orderDateKey Table Alias: fis Field Alias: maxAmt
8
Select examples * select 'just some text' as txt
select getdate() as dt select City from DimGeography select lastName from vTargetMail select color from (select 'blue' as color) as colors Select * is bad, it eats memory! use [AdventureWorksDW2012] go select 'just some text' as txt select getdate() as dt select City from DimGeography select lastName from vTargetMail select color from (select 'blue' as color) as colors *
9
Functions and Expressions
UPPER() - Converts a field to upper case SUBSTR() - Returns part of a character expression LTRIM() – Remove spaces from left end of text field LEN() - Returns the length of a text field GETDATE() - Returns the system date and time CHARINDEX() – Returns start of string in another string Case When Beware of misuse
10
Sets Tables Views Sub-queries Common Table Expressions Regular tables
Temp tables Table objects Function return Views Sub-queries Common Table Expressions
11
Comparison Operators = < <= > <> ! (not) Between Exists
In Is [not] null Remember, they are record based not set based!
12
Joins * Types Joins work with any comparison operator!
Inner Outer Left Right Cross Full Self Exists Joins work with any comparison operator! Joins aren’t as much of a problem as data size! --Joins use Fruit go select f.fruitName, c.color from fruit f inner join colors c on f.colorKey = c.colorKey from colors c left outer join fruit f right outer join fruit f --Self join use [AdventureWorksDW2012] select c.AccountDescription, p.AccountDescription from DimAccount c left outer join DimAccount p on p.ParentAccountKey = c.AccountKey order by c.accountKey --exists select e.lastName from DimEmployee e where not exists (select * from FactResellerSales frs where frs.EmployeeKey = e.EmployeeKey) *
13
Common Table Expressions
CTE Create a set on the fly Can only be used in a single query Doesn’t actually create the set Think of it like an include Optimizer doesn’t see a separate set --Common Table Expressions with northAmerica as (select [SalesTerritoryKey], [SalesTerritoryRegion] from DimSalesTerritory where [SalesTerritoryGroup] = 'North America') select top 3 na.SalesTerritoryRegion, fis.SalesAmount from FactInternetSales fis inner join northAmerica na on na.SalesTerritoryKey = fis.SalesTerritoryKey *
14
Union * Combine 2 sets with matching fields Useful in replacing Case
Field count must match exactly Data types must be implicitly convertible First query dictates names Useful in replacing Case Implicitly removes duplicates Use ‘Union All’ to preserve duplicates --Union select distinct st.SalesTerritoryRegion from FactInternetSales fis inner join DimSalesTerritory st on fis.SalesTerritoryKey = st.SalesTerritoryKey union from FactResellerSales frs on frs.SalesTerritoryKey = st.SalesTerritoryKey *
15
Correlated Subquery * A necessary evil Alternatives
Appears in select list Subquery contains a join referencing the outer query Runs once for each record! Alternatives Join Creating a temp record set --Correlated Subquery select e.lastName ,(select max(SalesAmount) from FactResellerSales frs where frs.EmployeeKey = e.EmployeeKey) as maxSales from DimEmployee e , max(frs.salesAmount) inner join FactResellerSales frs on frs.EmployeeKey = e.EmployeeKey group by e.LastName *
16
Nulls What size dress does George wear?
Missing or inapplicable data Nulls in any relational operation result in null Nulls in string concatenation result in null When testing for True, nulls appear false Special functions Is null (in WHERE clause) Isnull() Coalesce()
17
Cursors * Procedural Slow More code than SQL Can be the only solution
--Seperate products into free, cheap and expensive select top 10 * from Production.Product --cursor version nvarchar(50) money char(10) if object_id('tempdb..#priceGroups') is not null drop table #priceGroups create table #priceGroups (prod nvarchar(50), priceGroup char(10)) declare prices cursor for select p.Name, p.ListPrice from [Production].Product p open prices fetch next from while = 0 begin = 0 insert into #priceGroups values 'free') > 0 < 100 insert into #priceGroups values 'cheap') >= 100 insert into #priceGroups values 'expensive') end close prices deallocate prices select * from #priceGroups --case version select Name, (case when listPrice = 0 then 'free' when listPrice > 0 and listPrice < 100 then 'cheap' when listPrice >= 100 then 'expensive' else 'priceless' end) as priceGroup from Production.Product --union version select Name, 'free' as priceGroup from Production.Product where ListPrice = 0 union select Name, 'cheap' as priceGroup from Production.Product where ListPrice between 0 and 100 select Name, 'expensive' as priceGroup from Production.Product where ListPrice > 100 *
18
Recursive SQL * Use a CTE Create an anchor condition Union All
Query again calling anchor Choose what you want outside the CTE --Recursive CTE with r as (select c.AccountKey as ChildAccountKey, c.ParentAccountKey, 0 as lvl from DimAccount c where c.ParentAccountKey is null union all select p.AccountKey, p.ParentAccountKey, lvl + 1 from DimAccount p inner join r on p.ParentAccountKey = r.ChildAccountKey ) select parent.AccountDescription as parent, child.AccountDescription as child, lvl from r inner join DimAccount child on r.ChildAccountKey = child.AccountKey inner join DimAccount parent on r.ParentAccountKey = parent.AccountKey order by lvl, parent *
19
It’s important to understand data!
Query system tables Profile data --Profile varchar(700) varchar(50) varchar(50) varchar(100) = '' = '' varchar(200) DROP TABLE [dbo].[dbProfile] IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[dbProfile]') AND type in (N'U')) --Recreate the profile table CREATE TABLE [dbo].[dbProfile]( [recordCnt] [int] NULL, [ColumnName] [varchar](50) NOT NULL, [TableName] [varchar](50) NOT NULL, [distinctCnt] [int] NULL, [fldSample] varchar(300) [NullCnt] [int] NULL, [nonNullCnt] [int] NULL, ) ON [PRIMARY] SELECT t.name AS table_name, declare dbSchema cursor for c.name AS column_name ORDER BY table_name INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID FROM sys.tables AS t while = 0 fetch next from open dbSchema begin EXEC = 'declare fldList cursor for select distinct ' + ' from ' open fldList fetch next from fldList while = 0 and < 200 + + ', ' end deallocate fldList close fldList = 'insert into dbProfile (TableName, ColumnName, recordCnt, distinctCnt, nonNullCnt, nullCnt, fldSample) ' +'count(distinct as distinctCnt, ' +'count(*) as recordCnt, ' +'select as TableName as ColumnName, ' + '''' + + '''' +'sum(case when 0 then 1 else 0 end) as NullCnt, ' +'sum(case when 0 then 0 else 1 end) as nonNullCnt, ' +' from ' begin try end try end catch begin catch deallocate dbSchema close dbSchema select * from dbProfile *
20
There’s a particular style to it…
Thinking in SQL There’s a particular style to it… Rob Hatton
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.