SQL空值陷阱【MySQL、Oracle】

SQL 是一种声明式的语言,我们只需要描述想要的结果(WHAT),而不关心数据库如何实现(HOW);虽然 SQL 比较容易学习,但是有一些容易混淆和出错的概念。今天就来说说 SQL 中的空值陷阱和避坑方法。

本文使用的示例表结构如下:

示例数据:

INSERT INTO departments VALUES 
        ( 10
        , 'Administration'
        , 200
        , 1700
        );

INSERT INTO departments VALUES 
        ( 20
        , 'Marketing'
        , 201
        , 1800
        );
                                
INSERT INTO departments VALUES 
        ( 30
        , 'Purchasing'
        , 114
        , 1700
        );
                
INSERT INTO departments VALUES 
        ( 40
        , 'Human Resources'
        , 203
        , 2400
        );

INSERT INTO departments VALUES 
        ( 50
        , 'Shipping'
        , 121
        , 1500
        );
                
INSERT INTO departments VALUES 
        ( 60 
        , 'IT'
        , 103
        , 1400
        );
                
INSERT INTO departments VALUES 
        ( 70 
        , 'Public Relations'
        , 204
        , 2700
        );
                
INSERT INTO departments VALUES 
        ( 80 
        , 'Sales'
        , 145
        , 2500
        );
                
INSERT INTO departments VALUES 
        ( 90 
        , 'Executive'
        , 100
        , 1700
        );

INSERT INTO departments VALUES 
        ( 100 
        , 'Finance'
        , 108
        , 1700
        );
                
INSERT INTO departments VALUES 
        ( 110 
        , 'Accounting'
        , 205
        , 1700
        );

INSERT INTO departments VALUES 
        ( 120 
        , 'Treasury'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 130 
        , 'Corporate Tax'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 140 
        , 'Control And Credit'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 150 
        , 'Shareholder Services'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 160 
        , 'Benefits'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 170 
        , 'Manufacturing'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 180 
        , 'Construction'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 190 
        , 'Contracting'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 200 
        , 'Operations'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 210 
        , 'IT Support'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 220 
        , 'NOC'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 230 
        , 'IT Helpdesk'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 240 
        , 'Government Sales'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 250 
        , 'Retail Sales'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 260 
        , 'Recruiting'
        , NULL
        , 1700
        );

INSERT INTO departments VALUES 
        ( 270 
        , 'Payroll'
        , NULL
        , 1700
        );




INSERT INTO jobs VALUES 
        ( 'AD_PRES'
        , 'President'
        , 20080
        , 40000
        );
INSERT INTO jobs VALUES 
        ( 'AD_VP'
        , 'Administration Vice President'
        , 15000
        , 30000
        );

INSERT INTO jobs VALUES 
        ( 'AD_ASST'
        , 'Administration Assistant'
        , 3000
        , 6000
        );

INSERT INTO jobs VALUES 
        ( 'FI_MGR'
        , 'Finance Manager'
        , 8200
        , 16000
        );

INSERT INTO jobs VALUES 
        ( 'FI_ACCOUNT'
        , 'Accountant'
        , 4200
        , 9000
        );

INSERT INTO jobs VALUES 
        ( 'AC_MGR'
        , 'Accounting Manager'
        , 8200
        , 16000
        );

INSERT INTO jobs VALUES 
        ( 'AC_ACCOUNT'
        , 'Public Accountant'
        , 4200
        , 9000
        );
INSERT INTO jobs VALUES 
        ( 'SA_MAN'
        , 'Sales Manager'
        , 10000
        , 20080
        );

INSERT INTO jobs VALUES 
        ( 'SA_REP'
        , 'Sales Representative'
        , 6000
        , 12008
        );

INSERT INTO jobs VALUES 
        ( 'PU_MAN'
        , 'Purchasing Manager'
        , 8000
        , 15000
        );

INSERT INTO jobs VALUES 
        ( 'PU_CLERK'
        , 'Purchasing Clerk'
        , 2500
        , 5500
        );

INSERT INTO jobs VALUES 
        ( 'ST_MAN'
        , 'Stock Manager'
        , 5500
        , 8500
        );
INSERT INTO jobs VALUES 
        ( 'ST_CLERK'
        , 'Stock Clerk'
        , 2008
        , 5000
        );

INSERT INTO jobs VALUES 
        ( 'SH_CLERK'
        , 'Shipping Clerk'
        , 2500
        , 5500
        );

INSERT INTO jobs VALUES 
        ( 'IT_PROG'
        , 'Programmer'
        , 4000
        , 10000
        );

INSERT INTO jobs VALUES 
        ( 'MK_MAN'
        , 'Marketing Manager'
        , 9000
        , 15000
        );

INSERT INTO jobs VALUES 
        ( 'MK_REP'
        , 'Marketing Representative'
        , 4000
        , 9000
        );

INSERT INTO jobs VALUES 
        ( 'HR_REP'
        , 'Human Resources Representative'
        , 4000
        , 9000
        );

INSERT INTO jobs VALUES 
        ( 'PR_REP'
        , 'Public Relations Representative'
        , 4500
        , 10500
        );




INSERT INTO employees VALUES 
        ( 100
        , 'Steven'
        , 'King'
        , 'SKING'
        , '515.123.4567'
        , DATE('2003-06-17')
        , 'AD_PRES'
        , 24000
        , NULL
        , NULL
        , 90
        );

INSERT INTO employees VALUES 
        ( 101
        , 'Neena'
        , 'Kochhar'
        , 'NKOCHHAR'
        , '515.123.4568'
        , DATE('2005-09-21')
        , 'AD_VP'
        , 17000
        , NULL
        , 100
        , 90
        );

INSERT INTO employees VALUES 
        ( 102
        , 'Lex'
        , 'De Haan'
        , 'LDEHAAN'
        , '515.123.4569'
        , DATE('2001-01-13')
        , 'AD_VP'
        , 17000
        , NULL
        , 100
        , 90
        );

INSERT INTO employees VALUES 
        ( 103
        , 'Alexander'
        , 'Hunold'
        , 'AHUNOLD'
        , '590.423.4567'
        , DATE('2006-01-03')
        , 'IT_PROG'
        , 9000
        , NULL
        , 102
        , 60
        );

INSERT INTO employees VALUES 
        ( 104
        , 'Bruce'
        , 'Ernst'
        , 'BERNST'
        , '590.423.4568'
        , DATE('2007-05-21')
        , 'IT_PROG'
        , 6000
        , NULL
        , 103
        , 60
        );

INSERT INTO employees VALUES 
        ( 105
        , 'David'
        , 'Austin'
        , 'DAUSTIN'
        , '590.423.4569'
        , DATE('2005-06-25')
        , 'IT_PROG'
        , 4800
        , NULL
        , 103
        , 60
        );

INSERT INTO employees VALUES 
        ( 106
        , 'Valli'
        , 'Pataballa'
        , 'VPATABAL'
        , '590.423.4560'
        , DATE('2006-02-05')
        , 'IT_PROG'
        , 4800
        , NULL
        , 103
        , 60
        );

INSERT INTO employees VALUES 
        ( 107
        , 'Diana'
        , 'Lorentz'
        , 'DLORENTZ'
        , '590.423.5567'
        , DATE('2007-02-07')
        , 'IT_PROG'
        , 4200
        , NULL
        , 103
        , 60
        );

INSERT INTO employees VALUES 
        ( 108
        , 'Nancy'
        , 'Greenberg'
        , 'NGREENBE'
        , '515.124.4569'
        , DATE('2002-08-17')
        , 'FI_MGR'
        , 12008
        , NULL
        , 101
        , 100
        );

INSERT INTO employees VALUES 
        ( 109
        , 'Daniel'
        , 'Faviet'
        , 'DFAVIET'
        , '515.124.4169'
        , DATE('2002-08-16')
        , 'FI_ACCOUNT'
        , 9000
        , NULL
        , 108
        , 100
        );

INSERT INTO employees VALUES 
        ( 110
        , 'John'
        , 'Chen'
        , 'JCHEN'
        , '515.124.4269'
        , DATE('2005-09-28')
        , 'FI_ACCOUNT'
        , 8200
        , NULL
        , 108
        , 100
        );

INSERT INTO employees VALUES 
        ( 111
        , 'Ismael'
        , 'Sciarra'
        , 'ISCIARRA'
        , '515.124.4369'
        , DATE('2005-09-30')
        , 'FI_ACCOUNT'
        , 7700
        , NULL
        , 108
        , 100
        );

INSERT INTO employees VALUES 
        ( 112
        , 'Jose Manuel'
        , 'Urman'
        , 'JMURMAN'
        , '515.124.4469'
        , DATE('2006-03-07')
        , 'FI_ACCOUNT'
        , 7800
        , NULL
        , 108
        , 100
        );

INSERT INTO employees VALUES 
        ( 113
        , 'Luis'
        , 'Popp'
        , 'LPOPP'
        , '515.124.4567'
        , DATE('2007-12-07')
        , 'FI_ACCOUNT'
        , 6900
        , NULL
        , 108
        , 100
        );

INSERT INTO employees VALUES 
        ( 114
        , 'Den'
        , 'Raphaely'
        , 'DRAPHEAL'
        , '515.127.4561'
        , DATE('2002-12-07')
        , 'PU_MAN'
        , 11000
        , NULL
        , 100
        , 30
        );

INSERT INTO employees VALUES 
        ( 115
        , 'Alexander'
        , 'Khoo'
        , 'AKHOO'
        , '515.127.4562'
        , DATE('2003-05-18')
        , 'PU_CLERK'
        , 3100
        , NULL
        , 114
        , 30
        );

INSERT INTO employees VALUES 
        ( 116
        , 'Shelli'
        , 'Baida'
        , 'SBAIDA'
        , '515.127.4563'
        , DATE('2005-12-24')
        , 'PU_CLERK'
        , 2900
        , NULL
        , 114
        , 30
        );

INSERT INTO employees VALUES 
        ( 117
        , 'Sigal'
        , 'Tobias'
        , 'STOBIAS'
        , '515.127.4564'
        , DATE('2005-07-24')
        , 'PU_CLERK'
        , 2800
        , NULL
        , 114
        , 30
        );

INSERT INTO employees VALUES 
        ( 118
        , 'Guy'
        , 'Himuro'
        , 'GHIMURO'
        , '515.127.4565'
        , DATE('2006-11-15')
        , 'PU_CLERK'
        , 2600
        , NULL
        , 114
        , 30
        );

INSERT INTO employees VALUES 
        ( 119
        , 'Karen'
        , 'Colmenares'
        , 'KCOLMENA'
        , '515.127.4566'
        , DATE('2007-08-10')
        , 'PU_CLERK'
        , 2500
        , NULL
        , 114
        , 30
        );

INSERT INTO employees VALUES 
        ( 120
        , 'Matthew'
        , 'Weiss'
        , 'MWEISS'
        , '650.123.1234'
        , DATE('2004-07-18')
        , 'ST_MAN'
        , 8000
        , NULL
        , 100
        , 50
        );

INSERT INTO employees VALUES 
        ( 121
        , 'Adam'
        , 'Fripp'
        , 'AFRIPP'
        , '650.123.2234'
        , DATE('2005-04-10')
        , 'ST_MAN'
        , 8200
        , NULL
        , 100
        , 50
        );

INSERT INTO employees VALUES 
        ( 122
        , 'Payam'
        , 'Kaufling'
        , 'PKAUFLIN'
        , '650.123.3234'
        , DATE('2003-05-01')
        , 'ST_MAN'
        , 7900
        , NULL
        , 100
        , 50
        );

INSERT INTO employees VALUES 
        ( 123
        , 'Shanta'
        , 'Vollman'
        , 'SVOLLMAN'
        , '650.123.4234'
        , DATE('2005-10-10')
        , 'ST_MAN'
        , 6500
        , NULL
        , 100
        , 50
        );

INSERT INTO employees VALUES 
        ( 124
        , 'Kevin'
        , 'Mourgos'
        , 'KMOURGOS'
        , '650.123.5234'
        , DATE('2007-11-16')
        , 'ST_MAN'
        , 5800
        , NULL
        , 100
        , 50
        );

INSERT INTO employees VALUES 
        ( 125
        , 'Julia'
        , 'Nayer'
        , 'JNAYER'
        , '650.124.1214'
        , DATE('2005-07-16')
        , 'ST_CLERK'
        , 3200
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 126
        , 'Irene'
        , 'Mikkilineni'
        , 'IMIKKILI'
        , '650.124.1224'
        , DATE('2006-09-28')
        , 'ST_CLERK'
        , 2700
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 127
        , 'James'
        , 'Landry'
        , 'JLANDRY'
        , '650.124.1334'
        , DATE('2007-01-14')
        , 'ST_CLERK'
        , 2400
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 128
        , 'Steven'
        , 'Markle'
        , 'SMARKLE'
        , '650.124.1434'
        , DATE('2008-03-08')
        , 'ST_CLERK'
        , 2200
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 129
        , 'Laura'
        , 'Bissot'
        , 'LBISSOT'
        , '650.124.5234'
        , DATE('2005-08-20')
        , 'ST_CLERK'
        , 3300
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 130
        , 'Mozhe'
        , 'Atkinson'
        , 'MATKINSO'
        , '650.124.6234'
        , DATE('2005-10-30')
        , 'ST_CLERK'
        , 2800
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 131
        , 'James'
        , 'Marlow'
        , 'JAMRLOW'
        , '650.124.7234'
        , DATE('2005-02-16')
        , 'ST_CLERK'
        , 2500
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 132
        , 'TJ'
        , 'Olson'
        , 'TJOLSON'
        , '650.124.8234'
        , DATE('2007-04-10')
        , 'ST_CLERK'
        , 2100
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 133
        , 'Jason'
        , 'Mallin'
        , 'JMALLIN'
        , '650.127.1934'
        , DATE('2004-06-14')
        , 'ST_CLERK'
        , 3300
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 134
        , 'Michael'
        , 'Rogers'
        , 'MROGERS'
        , '650.127.1834'
        , DATE('2006-08-26')
        , 'ST_CLERK'
        , 2900
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 135
        , 'Ki'
        , 'Gee'
        , 'KGEE'
        , '650.127.1734'
        , DATE('2007-12-12')
        , 'ST_CLERK'
        , 2400
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 136
        , 'Hazel'
        , 'Philtanker'
        , 'HPHILTAN'
        , '650.127.1634'
        , DATE('2008-02-06')
        , 'ST_CLERK'
        , 2200
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 137
        , 'Renske'
        , 'Ladwig'
        , 'RLADWIG'
        , '650.121.1234'
        , DATE('2003-07-14')
        , 'ST_CLERK'
        , 3600
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 138
        , 'Stephen'
        , 'Stiles'
        , 'SSTILES'
        , '650.121.2034'
        , DATE('2005-10-26')
        , 'ST_CLERK'
        , 3200
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 139
        , 'John'
        , 'Seo'
        , 'JSEO'
        , '650.121.2019'
        , DATE('2006-02-12')
        , 'ST_CLERK'
        , 2700
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 140
        , 'Joshua'
        , 'Patel'
        , 'JPATEL'
        , '650.121.1834'
        , DATE('2006-04-06')
        , 'ST_CLERK'
        , 2500
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 141
        , 'Trenna'
        , 'Rajs'
        , 'TRAJS'
        , '650.121.8009'
        , DATE('2003-10-17')
        , 'ST_CLERK'
        , 3500
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 142
        , 'Curtis'
        , 'Davies'
        , 'CDAVIES'
        , '650.121.2994'
        , DATE('2005-01-29')
        , 'ST_CLERK'
        , 3100
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 143
        , 'Randall'
        , 'Matos'
        , 'RMATOS'
        , '650.121.2874'
        , DATE('2006-03-15')
        , 'ST_CLERK'
        , 2600
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 144
        , 'Peter'
        , 'Vargas'
        , 'PVARGAS'
        , '650.121.2004'
        , DATE('2006-07-09')
        , 'ST_CLERK'
        , 2500
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 145
        , 'John'
        , 'Russell'
        , 'JRUSSEL'
        , '011.44.1344.429268'
        , DATE('2004-10-01')
        , 'SA_MAN'
        , 14000
        , .4
        , 100
        , 80
        );

INSERT INTO employees VALUES 
        ( 146
        , 'Karen'
        , 'Partners'
        , 'KPARTNER'
        , '011.44.1344.467268'
        , DATE('2005-01-05')
        , 'SA_MAN'
        , 13500
        , .3
        , 100
        , 80
        );

INSERT INTO employees VALUES 
        ( 147
        , 'Alberto'
        , 'Errazuriz'
        , 'AERRAZUR'
        , '011.44.1344.429278'
        , DATE('2005-03-10')
        , 'SA_MAN'
        , 12000
        , .3
        , 100
        , 80
        );

INSERT INTO employees VALUES 
        ( 148
        , 'Gerald'
        , 'Cambrault'
        , 'GCAMBRAU'
        , '011.44.1344.619268'
        , DATE('2007-10-15')
        , 'SA_MAN'
        , 11000
        , .3
        , 100
        , 80
        );

INSERT INTO employees VALUES 
        ( 149
        , 'Eleni'
        , 'Zlotkey'
        , 'EZLOTKEY'
        , '011.44.1344.429018'
        , DATE('2008-01-29')
        , 'SA_MAN'
        , 10500
        , .2
        , 100
        , 80
        );

INSERT INTO employees VALUES 
        ( 150
        , 'Peter'
        , 'Tucker'
        , 'PTUCKER'
        , '011.44.1344.129268'
        , DATE('2005-01-30')
        , 'SA_REP'
        , 10000
        , .3
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 151
        , 'David'
        , 'Bernstein'
        , 'DBERNSTE'
        , '011.44.1344.345268'
        , DATE('2005-03-24')
        , 'SA_REP'
        , 9500
        , .25
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 152
        , 'Peter'
        , 'Hall'
        , 'PHALL'
        , '011.44.1344.478968'
        , DATE('2005-08-20')
        , 'SA_REP'
        , 9000
        , .25
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 153
        , 'Christopher'
        , 'Olsen'
        , 'COLSEN'
        , '011.44.1344.498718'
        , DATE('2006-03-30')
        , 'SA_REP'
        , 8000
        , .2
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 154
        , 'Nanette'
        , 'Cambrault'
        , 'NCAMBRAU'
        , '011.44.1344.987668'
        , DATE('2006-12-09')
        , 'SA_REP'
        , 7500
        , .2
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 155
        , 'Oliver'
        , 'Tuvault'
        , 'OTUVAULT'
        , '011.44.1344.486508'
        , DATE('2007-11-23')
        , 'SA_REP'
        , 7000
        , .15
        , 145
        , 80
        );

INSERT INTO employees VALUES 
        ( 156
        , 'Janette'
        , 'King'
        , 'JKING'
        , '011.44.1345.429268'
        , DATE('2004-01-30')
        , 'SA_REP'
        , 10000
        , .35
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 157
        , 'Patrick'
        , 'Sully'
        , 'PSULLY'
        , '011.44.1345.929268'
        , DATE('2004-03-04')
        , 'SA_REP'
        , 9500
        , .35
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 158
        , 'Allan'
        , 'McEwen'
        , 'AMCEWEN'
        , '011.44.1345.829268'
        , DATE('2004-08-01')
        , 'SA_REP'
        , 9000
        , .35
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 159
        , 'Lindsey'
        , 'Smith'
        , 'LSMITH'
        , '011.44.1345.729268'
        , DATE('2005-03-10')
        , 'SA_REP'
        , 8000
        , .3
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 160
        , 'Louise'
        , 'Doran'
        , 'LDORAN'
        , '011.44.1345.629268'
        , DATE('2005-12-15')
        , 'SA_REP'
        , 7500
        , .3
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 161
        , 'Sarath'
        , 'Sewall'
        , 'SSEWALL'
        , '011.44.1345.529268'
        , DATE('2006-11-03')
        , 'SA_REP'
        , 7000
        , .25
        , 146
        , 80
        );

INSERT INTO employees VALUES 
        ( 162
        , 'Clara'
        , 'Vishney'
        , 'CVISHNEY'
        , '011.44.1346.129268'
        , DATE('2005-11-11')
        , 'SA_REP'
        , 10500
        , .25
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 163
        , 'Danielle'
        , 'Greene'
        , 'DGREENE'
        , '011.44.1346.229268'
        , DATE('2007-03-19')
        , 'SA_REP'
        , 9500
        , .15
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 164
        , 'Mattea'
        , 'Marvins'
        , 'MMARVINS'
        , '011.44.1346.329268'
        , DATE('2008-01-24')
        , 'SA_REP'
        , 7200
        , .10
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 165
        , 'David'
        , 'Lee'
        , 'DLEE'
        , '011.44.1346.529268'
        , DATE('2008-02-23')
        , 'SA_REP'
        , 6800
        , .1
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 166
        , 'Sundar'
        , 'Ande'
        , 'SANDE'
        , '011.44.1346.629268'
        , DATE('2008-03-24')
        , 'SA_REP'
        , 6400
        , .10
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 167
        , 'Amit'
        , 'Banda'
        , 'ABANDA'
        , '011.44.1346.729268'
        , DATE('2008-04-21')
        , 'SA_REP'
        , 6200
        , .10
        , 147
        , 80
        );

INSERT INTO employees VALUES 
        ( 168
        , 'Lisa'
        , 'Ozer'
        , 'LOZER'
        , '011.44.1343.929268'
        , DATE('2005-03-11')
        , 'SA_REP'
        , 11500
        , .25
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 169  
        , 'Harrison'
        , 'Bloom'
        , 'HBLOOM'
        , '011.44.1343.829268'
        , DATE('2006-03-23')
        , 'SA_REP'
        , 10000
        , .20
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 170
        , 'Tayler'
        , 'Fox'
        , 'TFOX'
        , '011.44.1343.729268'
        , DATE('2006-01-24')
        , 'SA_REP'
        , 9600
        , .20
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 171
        , 'William'
        , 'Smith'
        , 'WSMITH'
        , '011.44.1343.629268'
        , DATE('2007-02-23')
        , 'SA_REP'
        , 7400
        , .15
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 172
        , 'Elizabeth'
        , 'Bates'
        , 'EBATES'
        , '011.44.1343.529268'
        , DATE('2007-03-24')
        , 'SA_REP'
        , 7300
        , .15
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 173
        , 'Sundita'
        , 'Kumar'
        , 'SKUMAR'
        , '011.44.1343.329268'
        , DATE('2008-04-21')
        , 'SA_REP'
        , 6100
        , .10
        , 148
        , 80
        );

INSERT INTO employees VALUES 
        ( 174
        , 'Ellen'
        , 'Abel'
        , 'EABEL'
        , '011.44.1644.429267'
        , DATE('2004-05-11')
        , 'SA_REP'
        , 11000
        , .30
        , 149
        , 80
        );

INSERT INTO employees VALUES 
        ( 175
        , 'Alyssa'
        , 'Hutton'
        , 'AHUTTON'
        , '011.44.1644.429266'
        , DATE('2005-03-19')
        , 'SA_REP'
        , 8800
        , .25
        , 149
        , 80
        );

INSERT INTO employees VALUES 
        ( 176
        , 'Jonathon'
        , 'Taylor'
        , 'JTAYLOR'
        , '011.44.1644.429265'
        , DATE('2006-03-24')
        , 'SA_REP'
        , 8600
        , .20
        , 149
        , 80
        );

INSERT INTO employees VALUES 
        ( 177
        , 'Jack'
        , 'Livingston'
        , 'JLIVINGS'
        , '011.44.1644.429264'
        , DATE('2006-04-23')
        , 'SA_REP'
        , 8400
        , .20
        , 149
        , 80
        );

INSERT INTO employees VALUES 
        ( 178
        , 'Kimberely'
        , 'Grant'
        , 'KGRANT'
        , '011.44.1644.429263'
        , DATE('2007-05-24')
        , 'SA_REP'
        , 7000
        , .15
        , 149
        , NULL
        );

INSERT INTO employees VALUES 
        ( 179
        , 'Charles'
        , 'Johnson'
        , 'CJOHNSON'
        , '011.44.1644.429262'
        , DATE('2008-01-04')
        , 'SA_REP'
        , 6200
        , .10
        , 149
        , 80
        );

INSERT INTO employees VALUES 
        ( 180
        , 'Winston'
        , 'Taylor'
        , 'WTAYLOR'
        , '650.507.9876'
        , DATE('2006-01-24')
        , 'SH_CLERK'
        , 3200
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 181
        , 'Jean'
        , 'Fleaur'
        , 'JFLEAUR'
        , '650.507.9877'
        , DATE('2006-02-23')
        , 'SH_CLERK'
        , 3100
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 182
        , 'Martha'
        , 'Sullivan'
        , 'MSULLIVA'
        , '650.507.9878'
        , DATE('2007-06-21')
        , 'SH_CLERK'
        , 2500
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 183
        , 'Girard'
        , 'Geoni'
        , 'GGEONI'
        , '650.507.9879'
        , DATE('2008-02-03')
        , 'SH_CLERK'
        , 2800
        , NULL
        , 120
        , 50
        );

INSERT INTO employees VALUES 
        ( 184
        , 'Nandita'
        , 'Sarchand'
        , 'NSARCHAN'
        , '650.509.1876'
        , DATE('2004-01-27')
        , 'SH_CLERK'
        , 4200
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 185
        , 'Alexis'
        , 'Bull'
        , 'ABULL'
        , '650.509.2876'
        , DATE('2005-02-20')
        , 'SH_CLERK'
        , 4100
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 186
        , 'Julia'
        , 'Dellinger'
        , 'JDELLING'
        , '650.509.3876'
        , DATE('2006-06-24')
        , 'SH_CLERK'
        , 3400
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 187
        , 'Anthony'
        , 'Cabrio'
        , 'ACABRIO'
        , '650.509.4876'
        , DATE('2007-02-07')
        , 'SH_CLERK'
        , 3000
        , NULL
        , 121
        , 50
        );

INSERT INTO employees VALUES 
        ( 188
        , 'Kelly'
        , 'Chung'
        , 'KCHUNG'
        , '650.505.1876'
        , DATE('2005-06-14')
        , 'SH_CLERK'
        , 3800
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 189
        , 'Jennifer'
        , 'Dilly'
        , 'JDILLY'
        , '650.505.2876'
        , DATE('2005-08-13')
        , 'SH_CLERK'
        , 3600
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 190
        , 'Timothy'
        , 'Gates'
        , 'TGATES'
        , '650.505.3876'
        , DATE('2006-07-11')
        , 'SH_CLERK'
        , 2900
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 191
        , 'Randall'
        , 'Perkins'
        , 'RPERKINS'
        , '650.505.4876'
        , DATE('2007-12-19')
        , 'SH_CLERK'
        , 2500
        , NULL
        , 122
        , 50
        );

INSERT INTO employees VALUES 
        ( 192
        , 'Sarah'
        , 'Bell'
        , 'SBELL'
        , '650.501.1876'
        , DATE('2004-02-04')
        , 'SH_CLERK'
        , 4000
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 193
        , 'Britney'
        , 'Everett'
        , 'BEVERETT'
        , '650.501.2876'
        , DATE('2005-03-03')
        , 'SH_CLERK'
        , 3900
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 194
        , 'Samuel'
        , 'McCain'
        , 'SMCCAIN'
        , '650.501.3876'
        , DATE('2006-07-01')
        , 'SH_CLERK'
        , 3200
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 195
        , 'Vance'
        , 'Jones'
        , 'VJONES'
        , '650.501.4876'
        , DATE('2007-03-17')
        , 'SH_CLERK'
        , 2800
        , NULL
        , 123
        , 50
        );

INSERT INTO employees VALUES 
        ( 196
        , 'Alana'
        , 'Walsh'
        , 'AWALSH'
        , '650.507.9811'
        , DATE('2006-04-24')
        , 'SH_CLERK'
        , 3100
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 197
        , 'Kevin'
        , 'Feeney'
        , 'KFEENEY'
        , '650.507.9822'
        , DATE('2006-05-23')
        , 'SH_CLERK'
        , 3000
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 198
        , 'Donald'
        , 'OConnell'
        , 'DOCONNEL'
        , '650.507.9833'
        , DATE('2007-06-21')
        , 'SH_CLERK'
        , 2600
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 199
        , 'Douglas'
        , 'Grant'
        , 'DGRANT'
        , '650.507.9844'
        , DATE('2008-01-13')
        , 'SH_CLERK'
        , 2600
        , NULL
        , 124
        , 50
        );

INSERT INTO employees VALUES 
        ( 200
        , 'Jennifer'
        , 'Whalen'
        , 'JWHALEN'
        , '515.123.4444'
        , DATE('2003-09-17')
        , 'AD_ASST'
        , 4400
        , NULL
        , 101
        , 10
        );

INSERT INTO employees VALUES 
        ( 201
        , 'Michael'
        , 'Hartstein'
        , 'MHARTSTE'
        , '515.123.5555'
        , DATE('2004-02-17')
        , 'MK_MAN'
        , 13000
        , NULL
        , 100
        , 20
        );

INSERT INTO employees VALUES 
        ( 202
        , 'Pat'
        , 'Fay'
        , 'PFAY'
        , '603.123.6666'
        , DATE('2005-08-17')
        , 'MK_REP'
        , 6000
        , NULL
        , 201
        , 20
        );

INSERT INTO employees VALUES 
        ( 203
        , 'Susan'
        , 'Mavris'
        , 'SMAVRIS'
        , '515.123.7777'
        , DATE('2002-06-07')
        , 'HR_REP'
        , 6500
        , NULL
        , 101
        , 40
        );

INSERT INTO employees VALUES 
        ( 204
        , 'Hermann'
        , 'Baer'
        , 'HBAER'
        , '515.123.8888'
        , DATE('2002-06-07')
        , 'PR_REP'
        , 10000
        , NULL
        , 101
        , 70
        );

INSERT INTO employees VALUES 
        ( 205
        , 'Shelley'
        , 'Higgins'
        , 'SHIGGINS'
        , '515.123.8080'
        , DATE('2002-06-07')
        , 'AC_MGR'
        , 12008
        , NULL
        , 101
        , 110
        );

INSERT INTO employees VALUES 
        ( 206
        , 'William'
        , 'Gietz'
        , 'WGIETZ'
        , '515.123.8181'
        , DATE('2002-06-07')
        , 'AC_ACCOUNT'
        , 8300
        , NULL
        , 205
        , 110
        );
View Code

NULL 即是空

在数据库中,空值(NULL)是一个特殊的值,通常用于表示缺失值或者不适用的值。比如,填写问卷时不愿意透露某些信息会导致录入项的缺失,在公司的组织结构中总会有一个人(董事长/总经理)没有上级领导。

首先一点,空值与数字 0 并不相同。假如我问你:你的钱包里有多少钱?如果你知道里面没有钱,可以说是零;如果你不确定,那么就是未知,但不能说没有。当我们需要创建一个表来存储这个信息的时候,应该是 NULL;除非我们能够确定钱包里面没有钱或者有多少钱。

另外,空值与空字符串('')也不相同,原因和上面类似。但是 Oracle 是一个例外,我们会在下文具体讨论。

在大多数编程语言中,访问 null 值通常会导致错误;但是 SQL 不会出错,只是会影响到运算的结果而已。

三值逻辑

在大多数编程语言中,逻辑运算的结果只有两种情况,不是真(True)就是假(False)。但是对于 SQL 而言,逻辑运算还可能是未知(Unknown):


引入三值逻辑主要是为了支持 NULL,因为 NULL 代表的是未知数据。因此,SQL 中的逻辑运算与(AND)、或(OR)以及非(NOT)的结果如下:


对于 AND 运算符而言,真和未知的与运算有可能是真,也有可能是假;因此,最终的结果是未知。

SQL 中的 WHERE、HAVING 以及 CASE WHEN 子句只返回逻辑运算结果为真的数据,不返回结果为假或未知的数据。

空值比较

当我们使用比较运算符(=、<>、<、> 等)与 NULL 进行比较时,结果既不是真也不是假,而是未知;因为 NULL 表示未知,也就意味着可能是任何值。以下运算的结果都是未知:

NULL = 0
NULL <> 0
NULL <= 0
NULL = NULL
NULL != NULL

NULL 与任何值都不相等,甚至两个 NULL 也不想等;因为我们不能说两个未知的值相同,也不能说它们不相同。

对于比较运算而言,NULL 和 NULL 不相同;但是某些 SQL 子句中的 NULL 值被看作相同的值,例如 GROUP BY。具体参考下文。

那么,如何判断一个值是否是 NULL 呢?为此,SQL 引入了两个谓词(WHERE 子句):IS NULL和IS NOT NULL。以下示例用于查找 manager 为空的员工: 

-- 使用比较运算符判断空值
SELECT employee_id, first_name, last_name, manager_id
  FROM employees
 WHERE manager_id = NULL;
employee_id|first_name|last_name|manager_id|
-----------|----------|---------|----------|

-- 使用 IS NULL 判断空值
SELECT employee_id, first_name, last_name, manager_id
  FROM employees
 WHERE manager_id IS NULL;
employee_id|first_name|last_name|manager_id|
-----------|----------|---------|----------|
        100|Steven    |King     |          |

其中,第一个查询使用比较运算符判断空值,不会返回任何结果;第二个查询使用 IS NULL 判断空值,返回了正确的结果。

除了标准的IS [NOT] NULL之外,还有一些数据库扩展的运算符可以用于空值比较:

-- MySQL
SELECT employee_id, first_name, last_name, manager_id
  FROM employees
 WHERE manager_id <=> NULL;
employee_id|first_name|last_name|manager_id|
-----------|----------|---------|----------|
        100|Steven    |King     |          |

MySQL 中的<=>可以用于等值比较,支持两个 NULL 值。

以下查询的结果也不会返回任何结果:

SELECT employee_id, first_name, last_name, manager_id
  FROM employees
 WHERE (1 = NULL) OR (1 != NULL);

因为根据上面的三值逻辑,两个未知结果的 OR 运算最终还是未知。

前文我们说过,空字符串不是 NULL;但是 Oracle 中的空字符串被看作 NULL。例如: 

-- Oracle
SELECT 1
  FROM dual
 WHERE '' IS NULL;
VAL|
---|
  1|

-- 其他数据库
SELECT 1 AS val
 WHERE '' IS NULL;
val|
---|

当然,我们如果使用等值(=)运算符判断空字符串与 NULL,结果仍然为空。

NOT IN 与空值

对于 WHERE 条件中的 IN 和 NOT IN 运算符,使用的是等值比较。所以如果 NOT IN 碰到了 NULL 值,永远不会返回任何结果。例如:

SELECT employee_id, first_name, last_name, manager_id
FROM employees
WHERE 1 NOT IN (NULL, 2);

因为上面的条件实际上等价于:

SELECT employee_id, first_name, last_name, manager_id
FROM employees
WHERE 1 != NULL AND 1 != 2;

1 不等于 NULL 的结果是未知,1 不等于 2 的结果是真,未知和真的 AND 运算结果还是未知。

如果使用 NOT IN,一定要确保括号中的值不会出现 NULL;或者尽量使用 NOT EXISTS。

函数与空值

一般来说,函数和表达式的参数中如果存在 NULL,其结果也是 NULL。当然也有一些例外,比如聚合函数。

以下查询返回的都是 NULL:

SELECT ABS(NULL), 1 + NULL
  FROM employees
 WHERE employee_id = 100;
ABS(NULL)|1 + NULL|
---------|--------|
   [NULL]|  [NULL]|

一个未知值的绝对值仍然未知,1 加上一个未知值结果还是未知。

但是一个常见的例外是字符串与 NULL 的连接:

-- Oracle
SELECT CONCAT('Hello', NULL)
  FROM employees
 WHERE employee_id = 100;
CONCAT('HELLO',NULL)|
--------------------|
Hello               |

-- MySQL
SELECT CONCAT('Hello', NULL)
  FROM employees
 WHERE employee_id = 100;
CONCAT('Hello', NULL)|
---------------------|
               [NULL]|

Oracle 将 NULL 看作空字符串,所以查询结果为“Hello”;MySQL 中 NULL 参数导致 CONCAT 函数结果为 NULL;SQLite 没有提供 CONCAT 函数。

另外,Oracle 中的 || 也将 NULL 看作空字符串;其他数据库 || 中的 NULL 将参数会产生 NULL 结果。

聚合函数(SUM、COUNT、AVG 等)通常会在进行计算之前删除 NULL 数据:

SELECT SUM(salary + commission_pct) sum1,
       SUM(salary) + SUM(commission_pct) sum2,
       COUNT(salary),
       COUNT(commission_pct)
  FROM employees;
SUM1    |SUM2    |COUNT(SALARY)|COUNT(COMMISSION_PCT)|
--------|--------|-------------|---------------------|
311507.8|691423.8|          107|                   35|

第一个 SUM 函数返回的是 salary 和 commission_pct 都不为空的数据总和;第而个 SUM 函数返回的是 salary 不为空的数据总和加上 commission_pct 不为空的数据总和,所以比第一个数据大;COUNT 函数结果显示 salary 有 107 条记录不为空,commission_pct 只有 35 条记录不为空。

如果输入数据都是 NULL 值,除了 COUNT 函数之外的其他聚合函数返回 NULL:

SELECT COUNT(*), COUNT(commission_pct), AVG(commission_pct), SUM(commission_pct)
  FROM employees
 WHERE commission_pct IS NULL;
COUNT(*)|COUNT(COMMISSION_PCT)|AVG(COMMISSION_PCT)|SUM(COMMISSION_PCT)|
--------|---------------------|-------------------|-------------------|
      72|                    0|             [NULL]|             [NULL]|

COUNT(*) 总是返回数据的行数,不受空值的影响;COUNT(commission_pct) 返回了零;AVG 和 SUM 返回了 NULL。

DISTINCT、GROUP BY、UNION 与空值

SQL 中的分组操作将所有的 NULL 值分到同一个组,包括 DISTINCT、GROUP BY 以及窗口函数中的 PARTITION BY。例如: 

SELECT DISTINCT commission_pct
  FROM employees;
commission_pct|
--------------|
        [NULL]|
          0.40|
          0.30|
          0.20|
          0.25|
          0.15|
          0.35|
          0.10|

SELECT commission_pct
  FROM employees
 GROUP BY commission_pct;
commission_pct|
--------------|
        [NULL]|
          0.40|
          0.30|
          0.20|
          0.25|
          0.15|
          0.35|
          0.10|

从上面的示例可以看出,commission_pct 为空的数据有 72 条,但是分组之后只有一个 NULL 组。

除此之外,UNION 操作符也将所有的 NULL 看作相同值:

SELECT manager_id
  FROM employees
 WHERE manager_id IS NULL
 UNION
SELECT manager_id
  FROM employees
 WHERE manager_id IS NULL;
manager_id|
----------|
    [NULL]|

如果将 UNION 换成 UNION ALL,查询结果将会保留 2 个 NULL 值。

ORDER BY 与空值

SQL 标准没有定义 NULL 值的排序顺序,但是为 ORDER BY 定义了 NULLS FIRST 和 NULLS LAST 选项,用于明确指定空值排在其他数据之前或者之后。

不同数据库对此提供了不同的实现:

SELECT employee_id, manager_id
  FROM employees
 WHERE employee_id IN (100, 101, 102)
 ORDER BY manager_id;

-- Oracle
EMPLOYEE_ID|MANAGER_ID|
-----------|----------|
        101|       100|
        102|       100|
        100|    [NULL]|

-- MySQL
employee_id|manager_id|
-----------|----------|
        100|    [NULL]|
        101|       100|
        102|       100|

其中,Oracle 默认将 NULL 作为最大值,升序时排在最后;MySQL默认将 NULL 作为最小值,升序时排在最前。

另外,Oracle提供了扩展的 NULLS FIRST 和 NULLS LAST 选项:

-- Oracle
SELECT employee_id, manager_id
  FROM employees
 WHERE employee_id IN (100, 101, 102)
 ORDER BY manager_id NULLS FIRST;
employee_id|manager_id|
-----------|----------|
        100|    [NULL]|
        101|       100|
        102|       100|

我们也可以使用 CASE 表达式实现类似的效果。以下示例与 NULLS LAST 作用相同,而且所有数据库都可以使用:

SELECT employee_id, manager_id
  FROM employees
 WHERE employee_id IN (100, 101, 102)
 ORDER BY CASE WHEN manager_id IS NULL THEN 1
               ELSE 0
          END,
          manager_id;
employee_id|manager_id|
-----------|----------|
        101|       100|
        102|       100|
        100|    [NULL]|

首先,CASE 表达式将 manager_id 为空的数据转换为 1,非空的数据转换为 0,所以空值排在其他数据之后;第二个排序字段 manager_id 确保了非空的数据从小到大排序。

空值处理函数

由于空值的特殊性,我们在分析数据时经常需要进行空值和其他值的转换。为此,SQL 提供了两个标准的空值函数:COALESCE 和 NULLIF。

COALESCE(exp1, exp2, …) 函数用于将 NULL 转换为其他值。当 exp1 不为空时返回 exp1,否则检查 exp2;如果 exp2 不为空时返回 exp2,依次类推。例如:

SELECT COALESCE(NULL, NULL, 3)
  FROM employees
 WHERE employee_id = 100;
COALESCE(NULL, NULL, 3)|
-----------------------|
                      3|

由于前面两个参数都是 NULL,COALESCE 最终返回了 3。

COALESCE 函数也可以使用 CASE 表达式改写如下:

CASE WHEN exp1 IS NOT NULL THEN exp1
     WHEN exp2 IS NOT NULL THEN exp2
     ...
     ELSE expN
END

NULLIF(exp1, exp2) 函数用于将指定值转换为 NULL。当 exp1 等于 exp2 时,返回 NULL;否则,返回 exp1 。NULLIF 最常见的用途是防止除零错误,例如:

SELECT 1 / NULLIF(0, 0) -- 1 / 0
FROM employees
WHERE employee_id = 100;

示例中的 NULLIF 将第一个零转换为 NULL,因此查询结果返回 NULL;如果直接使用 1 / 0,查询将会返回除零错误。MySQL 中的除零错误由 sql_mode 变量控制。

NULLIF 函数同样可以使用 CASE 表达式改写如下:

CASE WHEN exp1 = exp2 THEN NULL
ELSE exp1
END

利用 CASE 表达式,我们还可以轻松实现多个值到 NULL 的转换:

CASE WHEN expr IN (value1, value2, …)
THEN NULL
ELSE expr
END

COALESCE 和 NULLIF 实际上是 CASE 表达式的两种缩写形式。

除了标准 SQL 函数之外,数据库还提供了一些专用的函数:

  • Oracle 中的 NVL(expr1, expr2) 相当于 2 个参数的 COALESCE。另外,NVL2(expr1, expr2, expr3) 如果第一个参数不为空,返回第二个参数的值;否则,返回第三个参数的值;
  • MySQL 中的 IFNULL(expr1, expr2) 相当于 2 个参数的 COALESCE。另外,IF(expr1, expr2, expr3) 如果第一个参数为真(expr1 <> 0 并且 expr1 不为空),返回第二个参数的值;否则,返回第三个参数的值;

字段约束与空值

如果不允许字段中存在未知或者缺失的数据,可以使用字段的 NOT NULL 约束。

对于唯一约束(UNIQUE),多个 NULL 被看作是不同的值;因此,唯一约束字段中可以存在多个空值。不过 SQL Server 是个例外:

CREATE TABLE t_unique(id INT UNIQUE);
INSERT INTO t_unique VALUES(1);
INSERT INTO t_unique VALUES(NULL);
INSERT INTO t_unique VALUES(NULL); 

SELECT * FROM t_unique;
id|
------|
[NULL]|
[NULL]|
1|

SELECT * FROM t_unique;
id|
------|
[NULL]|

如果是复合索引,情况略有不同:

CREATE TABLE t_unique2(c1 INT, c2 INT, UNIQUE(c1,c2));

INSERT INTO t_unique2 VALUES(1, 1);
INSERT INTO t_unique2 VALUES(NULL, NULL);
INSERT INTO t_unique2 VALUES(NULL, NULL); -- SQL Server 产生唯一键冲突错误
INSERT INTO t_unique2 VALUES(1, NULL);
INSERT INTO t_unique2 VALUES(1, NULL); -- Oracle 和 SQL Server 产生唯一键冲突错误

其中,SQL Server 只允许有一个记录的全部索引字段为空;如果某个字段不为空,Oracle 和 SQL Server 只允许有一个记录的其他索引字段为空。

另外,检查约束(CHECK)对于 NULL 的处理与 WHERE 条件正好相反:只要数据的检查结果不是假都可以插入成功。例如: 

CREATE TABLE t_check (
  c1 INT CHECK (c1 >= 0),
  c2 INT CHECK (c2 >= 0),
  CHECK (c1 + c2 <= 100)
);

INSERT INTO t_check VALUES (5, 5);
INSERT INTO t_check VALUES (NULL, NULL);
INSERT INTO t_check VALUES (200, NULL);

SELECT * FROM t_check;
c1    |c2    |
------|------|
     5|     5|
[NULL]|[NULL]|
   200|[NULL]|

如果 c1 和 c2 都有值的话,都必须大于等于零并且和值小于等于 100;c1 和 c2 都可以为空;如果其中之一为空,另一个字段的值可以大于 100。

原文地址:https://www.cnblogs.com/johnvwan/p/12157792.html