<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-25819301</id><updated>2011-12-11T17:19:35.064-05:00</updated><category term='Dynamic SQL'/><category term='Holidays'/><category term='Adjacency List Model'/><category term='Nested Sets Model'/><category term='Temp Tables'/><category term='group by'/><category term='Range'/><category term='UDF'/><category term='Calendar Table'/><category term='Design'/><category term='Intersect'/><category term='ISO-8601'/><category term='Soundex'/><category term='Bit'/><category term='Null'/><category term='Boolean'/><category term='tolerance value'/><category term='Constraint'/><category term='Sets'/><category term='tables'/><category term='Identity'/><category term='Views'/><category term='Attribute Splitting'/><category term='COALESCE'/><category term='Parameter'/><category term='Rows'/><category term='dates'/><category term='ANSI_NULLS'/><category term='Formatting Data'/><category term='ISO-11179'/><category term='Union'/><category term='Settings'/><category term='Update'/><category term='WHERE Clause'/><category term='QUOTED_IDENTIFIER'/><category term='Query'/><category term='User Defined Functions'/><category term='Order'/><category term='Duplicates'/><category term='Records'/><category term='Refential Integrity'/><category term='Database Design'/><title type='text'>Joe Celko The SQL Apprentice</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default?start-index=101&amp;max-results=100'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>321</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-25819301.post-7639050521084334882</id><published>2007-12-28T13:24:00.000-05:00</published><updated>2007-12-28T13:55:40.411-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Defined Functions'/><category scheme='http://www.blogger.com/atom/ns#' term='UDF'/><title type='text'>A Strange Use of UDFs?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; started a new project recently and the .Net/SQL Server 2000 &lt;br /&gt;application I was hired to help with was developed by a large &lt;br /&gt;consulting firm. All the data access for the application is done via &lt;br /&gt;stored procedures, but most stored procedure data access is done &lt;br /&gt;via functions. So, you might have a SELECT inside a stored &lt;br /&gt;procedure that looks similar to this: &lt;br /&gt;&lt;br /&gt;SELECT e.LastName, et.TerritoryDescription, en.NADescription &lt;br /&gt;FROM Employees e &lt;br /&gt;LEFT JOIN fxEmpNat() en ON e.EmployeeID = en.EmployeeID &lt;br /&gt;LEFT JOIN fxEmpTer() et ON e.EmployeeID = et.EmployeeID &lt;br /&gt;WHERE e.LastName = 'Fuller' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And the function definitions are *similar* to those created in the &lt;br /&gt;script listed at the end of this post (using the Northwind database). &lt;br /&gt;I would solve the same problem using this approach: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT e.LastName, t.TerritoryDescription, n.NADescription &lt;br /&gt;FROM dbo.Employees e &lt;br /&gt;LEFT JOIN dbo.EmployeeTerritories et ON e.EmployeeID = et.EmployeeID &lt;br /&gt;JOIN dbo.Territories t ON et.TerritoryID = t.TerritoryID &lt;br /&gt;LEFT JOIN dbo.EmployeeNationality en ON e.EmployeeID = en.EmployeeID &lt;br /&gt;JOIN dbo.Nationality n ON en.NationalityID = n.NationalityID &lt;br /&gt;WHERE e.LastName = 'Fuller' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The original developers are long gone and no one currently working &lt;br /&gt;on the project knows why the function-centric approach was used. &lt;br /&gt;There are no security restrictions that would merit such an approach, &lt;br /&gt;and even if there were I would think a VIEW solution would be the &lt;br /&gt;more traditional approach. And there are only a couple of complicated &lt;br /&gt;relationships that one might want to "hide" from a less experienced &lt;br /&gt;developer that did not know the intricacies of the data. Anybody have &lt;br /&gt;any ideas when this approach would be justified? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- Addl. Table and Function Definitions &lt;br /&gt;CREATE TABLE Nationality &lt;br /&gt;( &lt;br /&gt; NationalityID int PRIMARY KEY, &lt;br /&gt; NADescription varchar(20) NOT NULL &lt;br /&gt;) &lt;br /&gt;go &lt;br /&gt;CREATE INDEX IX_Nationality_NADescription ON Nationality(NADescription) &lt;br /&gt;go &lt;br /&gt;INSERT Nationality VALUES (1,'America') &lt;br /&gt;INSERT Nationality VALUES (2,'Canada') &lt;br /&gt;INSERT Nationality VALUES (3,'Angola') &lt;br /&gt;go &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE EmployeeNationality &lt;br /&gt;( &lt;br /&gt; EmployeeID int, &lt;br /&gt; NationalityID int, &lt;br /&gt; CreateDate datetime &lt;br /&gt; CONSTRAINT PK_EmployeeNationality &lt;br /&gt;  PRIMARY KEY NONCLUSTERED &lt;br /&gt;  (EmployeeID,NationalityID,CreateDate) &lt;br /&gt;) &lt;br /&gt;go &lt;br /&gt;INSERT EmployeeNationality values(1,1,'01/01/80') &lt;br /&gt;INSERT EmployeeNationality values(1,1,'01/01/90') &lt;br /&gt;INSERT EmployeeNationality values(2,1,'01/01/90') &lt;br /&gt;INSERT EmployeeNationality values(3,2,'01/01/90') &lt;br /&gt;INSERT EmployeeNationality values(4,3,'01/01/90') &lt;br /&gt;go &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE FUNCTION fxEmpNat() &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;RETURNS TABLE &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AS &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;RETURN ( &lt;br /&gt; SELECT e.EmployeeID, n.NADescription &lt;br /&gt; FROM dbo.Employees e &lt;br /&gt; JOIN dbo.EmployeeNationality en &lt;br /&gt; ON e.EmployeeID = en.EmployeeID &lt;br /&gt; AND en.CreateDate = (SELECT MAX(en2.CreateDate) &lt;br /&gt; FROM EmployeeNationality en2 &lt;br /&gt; WHERE en.EmployeeID = en2.EmployeeID &lt;br /&gt; AND en.NationalityID = en2.NationalityID ) &lt;br /&gt; JOIN dbo.Nationality n ON en.NationalityID = n.NationalityID &lt;br /&gt; ) &lt;br /&gt;go &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE FUNCTION fxEmpTer() &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;RETURNS TABLE &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AS &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;RETURN ( &lt;br /&gt; SELECT e.EmployeeID, t.TerritoryDescription &lt;br /&gt; FROM dbo.Employees e &lt;br /&gt; JOIN dbo.EmployeeTerritories et ON e.EmployeeID = et.EmployeeID &lt;br /&gt; JOIN dbo.Territories t ON et.TerritoryID = t.TerritoryID &lt;br /&gt; ) &lt;br /&gt;go &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;One reason I can think of is job security.  This code will never port &lt;br /&gt;and can be read only by dialect speakers.  A function call cannot be &lt;br /&gt;optimized like a VIEW, so you are at risk for poor performance, as &lt;br /&gt;well as the maintenance problems, as time goes on. &lt;br /&gt;&lt;br /&gt;Another reason is that they are not SQL programmers and do not think &lt;br /&gt;in terms of declarations.  They want to see the familiar function call &lt;br /&gt;they know from procedural languages. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/bff15d436218d1d8/fccacaadf33bcd36?lnk=st&amp;q=#fccacaadf33bcd36"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7639050521084334882?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7639050521084334882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7639050521084334882' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7639050521084334882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7639050521084334882'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/strange-use-of-udfs.html' title='A Strange Use of UDFs?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4481956622931747553</id><published>2007-12-28T13:21:00.000-05:00</published><updated>2007-12-28T13:24:44.331-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dynamic SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Parameter'/><category scheme='http://www.blogger.com/atom/ns#' term='WHERE Clause'/><title type='text'>Using WHERE clause parameter</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;When I try to use an SP with parameter that is the WHERE clause it generates &lt;br /&gt;an error. &lt;br /&gt;&lt;br /&gt;E.g, &lt;br /&gt;&lt;br /&gt;@myWhere = varchar(200) &lt;br /&gt;&lt;br /&gt;AS &lt;br /&gt;&lt;br /&gt;SELECT x, y FROM skwi WHERE @myWhere &lt;br /&gt;&lt;br /&gt;myWhere = status = 7 AND LastName = 'Smith' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The problem is that the where clause is built conditionally in the program. &lt;br /&gt;Any advise and examples on how to accomplish would be appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; When I try to use an SP with parameter that is the WHERE clause it generates an error. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The short, dangerous kludge is to use Dynamic SQL. &lt;br /&gt;&lt;br /&gt;The right answer is to get out that old text book on Software &lt;br /&gt;Engineering and the chapters on coupling and cohesion of code &lt;br /&gt;modules.  Those rules still apply in SQL. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You are writing a "Britney Spears, Automobiles and Squids" module  -- &lt;br /&gt;you have no idea what it will do at run time, so it has absolutely no &lt;br /&gt;cohesion.  Instead of depending on every random future user to write &lt;br /&gt;proper SQL, you need to earn your salary and proper them with a well- &lt;br /&gt;defined module with a meaningful name and a known parameter list. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you want a general query tool, then use QA.  Application users &lt;br /&gt;should be kept away form it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/12c3fb92aba65b04/034d40b6ab7beb50?lnk=st&amp;q=#034d40b6ab7beb50"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4481956622931747553?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4481956622931747553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4481956622931747553' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4481956622931747553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4481956622931747553'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/using-where-clause-parameter.html' title='Using WHERE clause parameter'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-8415978772607003701</id><published>2007-12-27T10:25:00.000-05:00</published><updated>2007-12-27T10:26:27.034-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Union'/><category scheme='http://www.blogger.com/atom/ns#' term='group by'/><title type='text'>How do I group in a union?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a select statement that uses union to pull data from multiple &lt;br /&gt;databases and return them in a single recordset. I want to group these &lt;br /&gt;results using group by. How do I do that? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's what I have: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT EmployeeID, ProjectID &lt;br /&gt;FROM DB1.table1 &lt;br /&gt;UNION &lt;br /&gt;SELECT EmployeeID, ProjectID &lt;br /&gt;FROM DB2.table1 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This works fine but I want to group all projects by EmployeeID. I tried the &lt;br /&gt;following but it didn't work &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT EmployeeID, ProjectID &lt;br /&gt;FROM DB1.table1 &lt;br /&gt;UNION &lt;br /&gt;SELECT EmployeeID, ProjectID &lt;br /&gt;FROM DB2.table1 &lt;br /&gt;GROUP BY EmployeeID &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'd appreciate some help here. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;The results of a UNION do not have column names &lt;br /&gt;&lt;br /&gt;SELECT X.emp_id, COUNT(project_id) AS project_tot &lt;br /&gt;  FROM (SELECT emp_id, project_id &lt;br /&gt;          FROM DB1.Table1 &lt;br /&gt;        UNION &lt;br /&gt;        SELECT emp_id, project_id &lt;br /&gt;          FROM DB2.Table1) &lt;br /&gt;       AS X(emp_id, project_id) &lt;br /&gt; GROUP BY X.emp_id; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UNION ALL will be faster, if it is possible. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/764e15e34d72f522/0b228ec44557839f?lnk=st&amp;q=#0b228ec44557839f"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-8415978772607003701?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/8415978772607003701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=8415978772607003701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8415978772607003701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8415978772607003701'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/how-do-i-group-in-union.html' title='How do I group in a union?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3239937127283178331</id><published>2007-12-27T10:20:00.000-05:00</published><updated>2007-12-27T10:21:08.912-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Update'/><title type='text'>when calling UPDATE from the result set of a SELECT statement, is the order in which rows from the SELECT statement 100% geronteed?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;when calling UPDATE from the result set of a SELECT statement, is the order &lt;br /&gt;in which rows from the SELECT statement 100% geronteed? &lt;br /&gt;&lt;br /&gt;tableA &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;myid &lt;br /&gt;----------- &lt;br /&gt;0 &lt;br /&gt;1 &lt;br /&gt;2 &lt;br /&gt;3 &lt;br /&gt;4 &lt;br /&gt;5 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE tableB u &lt;br /&gt;SET myid = i.myid &lt;br /&gt;FROM tableA i &lt;br /&gt;ORDER BY myid &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Will this always update tableB with 5 since it is the last one? is this 100% &lt;br /&gt;garonteed to follow the order of the source result set? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;No. There is no ordering in a table by defintion. Since this strictly &lt;br /&gt;proprietary syntax it an do anything MS feels like next week.  You are &lt;br /&gt;just looking for the comfort of a 1960's sequential file system &lt;br /&gt;instead of learning to think in RDBMS. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/df07ca9f96c815f6/58c864ab052165a2?lnk=st&amp;q=#58c864ab052165a2"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3239937127283178331?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3239937127283178331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3239937127283178331' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3239937127283178331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3239937127283178331'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/when-calling-update-from-result-set-of.html' title='when calling UPDATE from the result set of a SELECT statement, is the order in which rows from the SELECT statement 100% geronteed?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3147250299544182315</id><published>2007-12-27T10:05:00.000-05:00</published><updated>2007-12-27T10:09:22.526-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tolerance value'/><title type='text'>Which values do NOT appear within a tolerance value Options</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a table of servers that receive updates on a regular basis &lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[tbl_ServerUpdate]( &lt;br /&gt; [ServerUpdateID] [int] NOT NULL, &lt;br /&gt; [Server] [nvarchar](256) NOT NULL, &lt;br /&gt; [UpdateStamp] [datetime] NOT NULL, &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I then have tolerance values in another table which I can get like this &lt;br /&gt;(they are in terms of minutes): &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE @Interval INT &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT  @Interval = IntervalValue &lt;br /&gt;FROM    tbl_Interval (NOLOCK) &lt;br /&gt;WHERE   IntervalID = 1 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to know which servers have NOT received an update within the &lt;br /&gt;tolerance value. For example, give me the set of Server that have not &lt;br /&gt;received an update in the last 5 (@Interval) minutes. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;What is an update_id?  What would it mean in a logical data model? &lt;br /&gt;Surely, you did NOT just physically number the rows in a table! &lt;br /&gt;&lt;br /&gt;This table also had no key, so I made an assumption that you want to &lt;br /&gt;use the (originally very long AND possibly in Chinese!) server names. &lt;br /&gt;But isn't the update interval logically an attribute of each server? &lt;br /&gt;Shouldn't it be in the Servers table?  I cannot see an interval &lt;br /&gt;floating around as an entity in itself. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Servers &lt;br /&gt;(server_name VARCHAR(25) NOT NULL PRIMARY KEY, &lt;br /&gt; update_stamp DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt; update_interval INTEGER NOT NULL &lt;br /&gt;  CHECK(update_interval &gt; 0), &lt;br /&gt; etc. &lt;br /&gt; ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you  need this a lot, put it in a VIEW. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW ExpiredServers (server_name) &lt;br /&gt;AS &lt;br /&gt;SELECT server_name &lt;br /&gt;  FROM Servers &lt;br /&gt; WHERE update_stamp &lt;br /&gt;      &lt; DATEADD(MI, -update_interval, CURRENT_TIMESTAMP); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;In the real world, everything is not a beautifully static picture of &lt;br /&gt;relational data. I didn't include the key because I don't think its relevant &lt;br /&gt;to the solution. But since you brought it up: is it better to have a natural &lt;br /&gt;key on a varchar or an identity key as an integer that doesn't really have &lt;br /&gt;any intrinsic business meaning &lt;br /&gt;&lt;br /&gt;? In theory, it should be the varchar, but in practice its more performant &lt;br /&gt;to index an int rather than a varchar(25). Is that not true? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The interval is not an attribute of the server, but rather an attribute of &lt;br /&gt;the update type. In my case, there are seven different minute intervals. So, &lt;br /&gt;in the end, I need to know - for each update type - which server did not &lt;br /&gt;receive it within the last [interval] (in terms of minutes). The interval is &lt;br /&gt;configurable by the operations group - sometimes they may want to be alerted &lt;br /&gt;when a server didn't receive an update in the last 3 minutes, sometimes in &lt;br /&gt;the last 10 minutes. They can change this real-time in the database. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am not a TSQL guru - thats why I use this newsgroup from time to time. I &lt;br /&gt;also have every one of your books on my shelf. However, the corporate world &lt;br /&gt;is NOT academic and there is a tradeoff between having an understandable &lt;br /&gt;data model that is easy to work with and having a data model that can serve &lt;br /&gt;as a model in CS405 (or whatever). Sometimes we have to denormalize or &lt;br /&gt;flatten data to be able to run reports in an acceptable time; sometimes we &lt;br /&gt;have to add bit columns that could easily be derived from another to improve &lt;br /&gt;query performance. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The balance you give is valuable, so I hope you continue to berate us when &lt;br /&gt;our designs violate, but I'll bet - despite all the companies you have &lt;br /&gt;worked with - you can't name one that had a data model that gave you a &lt;br /&gt;boner. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; is it better to have a natural key on a VARCHAR(n) or an IDENTITY  key [SIC] as an integer that doesn't really have any intrinsic business meaning?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How important is data integrity?  Why not use a pointer chain DB &lt;br /&gt;instead of mimicking it in SQL?  At least they have features to do &lt;br /&gt;garbage collection, restore chains, etc.  Eventually, denormalization &lt;br /&gt;and short-cuts will come back and bite you. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; In theory, it should be the VARCHAR, but in practice its more performant to index an INTEGER rather than a VARCHAR(25). Is that not true?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It depends on the product.  You automatically assumed indexing; look &lt;br /&gt;at hashing in Teradata.  Longer strings for keys lead to easy perfect &lt;br /&gt;hashing, which is always one probe as opposed to multiple probes with &lt;br /&gt;an index when the database gets large.  If you are using hidden &lt;br /&gt;pointer chains like SQL Anywhere to implement PK-FK, there is no &lt;br /&gt;difference.  SQL Server does have a lot of "code museum" problems and &lt;br /&gt;this is one of them; one type of simple B+ Tree index is used for all &lt;br /&gt;data types and distributions.  However, until you get to large DBs, it &lt;br /&gt;works fine and it will get a shot in the arm from 64-bit hardware, &lt;br /&gt;too. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; The interval is not an attribute of the server, but rather an attribute of the update type.  In my case, there are seven different minute intervals. So, in the end, I need to know - for each update type - which server did not receive it within the last [interval] (in terms of minutes). The interval is configurable by the operations group - sometimes they may want to be alerted when a server didn't receive an update in the last 3 minutes, sometimes in the last 10 minutes. They can change this real-time in the database.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A type is an attribute by definition, so what entity does the &lt;br /&gt;update_type belong to, if not a server?  I would think from this &lt;br /&gt;description, you would have seven columns for the logically different &lt;br /&gt;updates, and seven columns for their corresponding intervals.  Or is &lt;br /&gt;this a repeating group where not all update types apply to all servers &lt;br /&gt;and the update types can be changed? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I also have every one of your books on my shelf.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Neat!  Number 7 is out in 2008 February. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  .. I'll bet - despite all the companies you have worked with - you can't name one that had a data model that gave you a boner.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;LOL!  Remember what I do for a living -- this is like asking a doctor &lt;br /&gt;why all his patients are sick! &lt;br /&gt;&lt;br /&gt;The best one I can remember just off hand was for a credit management &lt;br /&gt;company.  They had just designed it and wanted a two day review from &lt;br /&gt;me.  The only real problem I found was that a bunch of the columns &lt;br /&gt;were stubbed in with a magical CHAR(1) NOT NULL data type; they were &lt;br /&gt;still working on the encodings and waiting for advise from legal. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Another one was a software company with a portal product that manages &lt;br /&gt;corporate software access.  We replaced ~60 tables with a nested set &lt;br /&gt;model that lead to ~6 tables for the core processes.  In fairness, the &lt;br /&gt;original model had grown over time from a denormalized model on a &lt;br /&gt;small platform to a mainframe tool.  People kept adding tables to it &lt;br /&gt;as a work-around and it had become a jungle. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/7b56e70b686f6e43/2cb7baed394c331a?lnk=st&amp;q=#2cb7baed394c331a"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3147250299544182315?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3147250299544182315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3147250299544182315' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3147250299544182315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3147250299544182315'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/which-values-do-not-appear-within.html' title='Which values do NOT appear within a tolerance value Options'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-963769786777561053</id><published>2007-12-27T10:02:00.000-05:00</published><updated>2007-12-27T10:04:38.305-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Null'/><category scheme='http://www.blogger.com/atom/ns#' term='Settings'/><category scheme='http://www.blogger.com/atom/ns#' term='QUOTED_IDENTIFIER'/><category scheme='http://www.blogger.com/atom/ns#' term='ANSI_NULLS'/><title type='text'>QUOTED_IDENTIFIER &amp; ANSI_NULLS Options</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;does anyone know how to keep QA from adding the lines setting these &lt;br /&gt;two options on and off along with blank lines at the beginning and end &lt;br /&gt;of every object you edit? i have searched quite a bit on this but &lt;br /&gt;haven't been able to come up with anything. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  is there a reason I wouldn't want to do this? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Conformance to ANSI/ISO Standards should be a goal in any shop, so you &lt;br /&gt;would not turn off options that bring you to that goal.  Why would you &lt;br /&gt;want to write your own database language? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.clients/browse_thread/thread/6f2df95eeeff2b00/ec13f8135447bc29?lnk=st&amp;q=#ec13f8135447bc29"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-963769786777561053?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/963769786777561053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=963769786777561053' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/963769786777561053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/963769786777561053'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/quotedidentifier-ansinulls-options.html' title='QUOTED_IDENTIFIER &amp; ANSI_NULLS Options'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6954431303497328343</id><published>2007-12-27T09:59:00.000-05:00</published><updated>2007-12-27T10:02:02.080-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Update'/><title type='text'>update table dateCol3 to the later of dateCol1 or dateCol2 Options</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;CREATE TABLE #tmp1(rowID int identity(1,1), dateCol1 datetime, dateCol2&lt;br /&gt;datetime, dateCol3 datetime)&lt;br /&gt;&lt;br /&gt;INSERT INTO #tmp1(dateCol1, dateCol2)&lt;br /&gt;SELECT '1/1/05', '2/1/05'&lt;br /&gt;UNION ALL SELECT '3/1/05', '3/7/05'&lt;br /&gt;UNION ALL SELECT '4/1/05', '3/20/05'&lt;br /&gt;UNION ALL SELECT '5/1/05', '5/13/05'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE #tmp1 SET dateCol3 = ?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If dateCol1 &gt; dateCol2 then update dateCol3 to dateCol1&lt;br /&gt;else&lt;br /&gt;update #tmp1 Set dateCol3 to dateCol2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am sure this is not the most normalized example, but what would be the&lt;br /&gt;tSql to update my table with the latest date in a row without having to do it&lt;br /&gt;in 2 queries?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I realize I could say&lt;br /&gt;&lt;br /&gt;update #tmp1 set datecol3 = datecol1 where datecol1 &gt; datecol2&lt;br /&gt;&lt;br /&gt;and then&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;update #tmp1 set datecol3 = datecol2 where datecol2 &gt; datecol1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there a way to do this in one query statement? What would that look like?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;If you followed ISO-11179 data element naming rules, avoided&lt;br /&gt;needlessly proprietary code, and put your date into the proper format&lt;br /&gt;for Standard SQL, would your posting look like this?&lt;br /&gt;&lt;br /&gt;CREATE TABLE Foobar&lt;br /&gt;(foobar_id INTEGER NOT NULL PRIMARY KEY,&lt;br /&gt;col1_date DATETIME NOT NULL,&lt;br /&gt;col2_date DATETIME NOT NULL,&lt;br /&gt;col3_date DATETIME);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Foobar(foobar_id, col1_date, col2_date)&lt;br /&gt;VALUES (42, '2005-01-01', '2005-02-01');&lt;br /&gt;Etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;IF col1_date &gt; col2_date&lt;br /&gt;THEN update col3_date to col1_date&lt;br /&gt;ELSE update col3_date to col2_date&lt;br /&gt;&lt;&lt; col3_date =" CASE"&gt; col2_date&lt;br /&gt;THEN col1_date&lt;br /&gt;ELSE col2_date END;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You have a few choices here.&lt;br /&gt;1) You can make col3_date into a computed column in proprietary syntax&lt;br /&gt;-- look it up.&lt;br /&gt;2) You can use the CASE expression to update col3_date; "UPDATE Foobar&lt;br /&gt;SET col3_date = CASE.. END;" Of course this still means that you have&lt;br /&gt;materialized computed data in violate of good design.&lt;br /&gt;3) You can put it in a VIEW, and drop col3_date from the base table.&lt;br /&gt;The code will always be right and portable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/d33927b9e7a9d483/a4c0dd21fa7d2e0f?lnk=st&amp;amp;q=#a4c0dd21fa7d2e0f"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6954431303497328343?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6954431303497328343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6954431303497328343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6954431303497328343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6954431303497328343'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/12/update-table-datecol3-to-later-of.html' title='update table dateCol3 to the later of dateCol1 or dateCol2 Options'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-5325462806287828740</id><published>2007-10-04T13:14:00.000-04:00</published><updated>2007-10-04T13:20:23.690-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rows'/><category scheme='http://www.blogger.com/atom/ns#' term='Records'/><category scheme='http://www.blogger.com/atom/ns#' term='Database Design'/><category scheme='http://www.blogger.com/atom/ns#' term='Query'/><category scheme='http://www.blogger.com/atom/ns#' term='tables'/><title type='text'>How to retrieve all records from 30th record to 50th record of a table?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a table named myTable. It is sorted by some column and there is &lt;br /&gt;no primery key or unique column.I want to retrieve all records from &lt;br /&gt;30th record to 50th record. How can I do this by a sql statement? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I have a table named myTable. It is sorted by some column and there is no primary key or unique column.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;BY DEFINITION: &lt;br /&gt;1) Tables have at least one key &lt;br /&gt;2) Tables have no ordering &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I want to retrieve all records from 30th record to 50th record. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) Rows are not anything like records &lt;br /&gt;2) Tables have no ordering &lt;br /&gt;&lt;br /&gt;Please read a book --ANY book -- are RDBMS.  You have gotten every &lt;br /&gt;basic concept wrong. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/b1ffe82b31d21579/83847f848c88b398#83847f848c88b398"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-5325462806287828740?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/5325462806287828740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=5325462806287828740' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5325462806287828740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5325462806287828740'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/10/how-to-retrieve-all-records-from-30th.html' title='How to retrieve all records from 30th record to 50th record of a table?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-7056044052394682684</id><published>2007-10-04T13:03:00.000-04:00</published><updated>2007-10-04T13:07:53.321-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dates'/><category scheme='http://www.blogger.com/atom/ns#' term='Query'/><category scheme='http://www.blogger.com/atom/ns#' term='tables'/><title type='text'>No idea where to start with Query</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I need some help with a query using SQL 2005 and I really don't know&lt;br /&gt;where to start.&lt;br /&gt;I have 3 columns: Date(dateTime), Name(varchar), Value(decimal)&lt;br /&gt;I need to retireive 3 values, one query or all, or one query for&lt;br /&gt;each. It makes no difference to me.&lt;br /&gt;&lt;br /&gt;1)For each Name I need to get the difference of current day's value&lt;br /&gt;and previous day's value&lt;br /&gt;(TodayValue- PreviousDayValue)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2)For each Name I need to get the sum of difference of yesterday's&lt;br /&gt;value and today's value for the current month&lt;br /&gt;So something like (Day1Value - Day2Value) + (Day2Value - Day3Value)&lt;br /&gt;+...+ (Day29Value - Day30Value)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3)Same as #2 but just for the current year.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any help would be greatly appreciated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;The best place to start is with DDL, so that people do not have to&lt;br /&gt;guess what the keys, constraints, Declarative Referential Integrity,&lt;br /&gt;data types, etc. in your schema are. If you know how, follow ISO-11179&lt;br /&gt;data element naming conventions and formatting rules. Sample data is&lt;br /&gt;also a good idea, along with clear specifications. It is very hard to&lt;br /&gt;debug code when you do not let us see it. What you did post was a pile&lt;br /&gt;of vague names and/or reserved words. Let's make it real and sensible:&lt;br /&gt;&lt;br /&gt;CREATE TABLE DogSchedule&lt;br /&gt;(walk_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,&lt;br /&gt;dog_name CHAR(15) NOT NULL,&lt;br /&gt;walk_kilometers DECIMAL (5,2) NOT NULL,&lt;br /&gt;PRIMARY KEY (walk_date, dog_name));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1)For each dog_name I need to get the difference of current day's &lt;br /&gt;value and previous day's value &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You did not tell us if you are sure that all days are represented in &lt;br /&gt;the table? Only one walk per day?  What constraint enforces that &lt;br /&gt;business rule? My point is that SQL is an integrated whole -- you &lt;br /&gt;cannot separate DDL and DML; they must work together! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next, you are going to be using the delta from day to day, so let's &lt;br /&gt;put that in a VIEW. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW DeltaDogWalks (walk_date, dog_name, delta_kilometers) &lt;br /&gt;AS &lt;br /&gt;SELECT D2.walk_date, D2.dog_name, &lt;br /&gt;      (D2.walk_kilometers - D1.walk_kilometers) &lt;br /&gt;  FROM DogSchedule AS D1, DogSchedule AS D2 &lt;br /&gt; WHERE D1.dog_name = D2.dog_name &lt;br /&gt;   AND D2.walk_date = DATEADD(DD, 1, D1.walk_date); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To sum the deltas, set up a report periods table that you can adjust: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE ReportPeriods &lt;br /&gt;(period_name CHAR(15) NOT NULL PRIMARY KEY, &lt;br /&gt; start_date DATETIME NOT NULL, &lt;br /&gt; end_date DATETIME NOT NULL, &lt;br /&gt; CHECK(start_date &lt; end_date)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now use a "walk_date BETWEEN start_date AND end_date" to group on the &lt;br /&gt;names of the reporting periods. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/a640bdb4c9dd43de/fdb468ef973e6619#fdb468ef973e6619"&gt;Original source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7056044052394682684?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7056044052394682684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7056044052394682684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7056044052394682684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7056044052394682684'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/10/no-idea-where-to-start-with-query.html' title='No idea where to start with Query'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-1121087623017008907</id><published>2007-08-09T09:08:00.000-04:00</published><updated>2007-08-09T09:09:47.475-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Query'/><title type='text'>A Strange Query Options</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Hi guys, &lt;br /&gt;&lt;br /&gt;I'm trying to work this query out in my head see if you can help me with it. &lt;br /&gt;I'll give you a little background information so you have the big picture. &lt;br /&gt;This is a real estate database, every home has an APN number it's a unique &lt;br /&gt;number that always means the same property.   When a company wants to list a &lt;br /&gt;home on the MLS to sell the home it gets an MLS number which is only unique &lt;br /&gt;to the instance the entity wants to sell that property, so in a span of a &lt;br /&gt;few years the same APN could go for sale several times and have several MLS &lt;br /&gt;Numbers, but maintain the same APN.     This database is setup so each row &lt;br /&gt;is an MLS Number. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need to make a list of all entries that qualify: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.  Find APN's with multiple entries &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2.  Narrow it down to only solds &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.  Only solds that have been modified in the last 3 years &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and it needs to generate a list of just DISTINCT APN's that qualify. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks, &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are.  We don't even know your data types, column or table &lt;br /&gt;names much less your codes!  Sample data is also a good idea, along &lt;br /&gt;with clear specifications.  It is very hard to debug code when you do &lt;br /&gt;not let us see it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; This is a real estate database, every home has an APN number it's a unique number that always means the same property.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Properties &lt;br /&gt;(apn INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; etc); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; When a company wants to list a home on the MLS to sell the home it gets an MLS number which is only unique to the instance the entity wants to sell that property, so in a span of a few years the same APN could go for sale several times and have several MLS Numbers, but maintain the same APN. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Listings &lt;br /&gt;(apn INTEGER NOT NULL &lt;br /&gt;   REFERENCES Properties(apn) &lt;br /&gt;   ON DELETE CASCADE &lt;br /&gt;   ON UPDATE CASCADE, &lt;br /&gt; start_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt; end_date DATETIME, -- null means current &lt;br /&gt; CHECK (start_date &lt; end_date), &lt;br /&gt; PRIMARY KEY (apn, start_date), &lt;br /&gt; mls INTEGER NOT NULL, &lt;br /&gt; listing_status CHAR(10) DEFAULT 'listed' NOT NULL &lt;br /&gt;    CHECK (listing_status IN ('listed', 'sold', 'reduced', etc)), &lt;br /&gt; asking_price DECIMAL(12,2) NOT NULL, &lt;br /&gt; etc); &lt;br /&gt;&lt;br /&gt;You also need a Calendar table, since this is a history schema. Google &lt;br /&gt;that. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I need to make a list of all entries that qualify: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.  Find APN's with multiple entries &lt;br /&gt;2.  Narrow it down to only solds &lt;br /&gt;3.  Only solds that have been modified in the last 3 years and it &lt;br /&gt;needs to generate a list of just DISTINCT APN's that qualify. &lt;&lt; &lt;br /&gt;&lt;br /&gt;Did you notice that you gave a step by step **procedure**, rather than &lt;br /&gt;a **declarative statement**?  You do not thinking SQL yet.  This is &lt;br /&gt;steps 1 and 2 as a query: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT apn, COUNT(*) AS listed_cnt &lt;br /&gt;  FROM Listings &lt;br /&gt; WHERE listing_status = 'sold' &lt;br /&gt; GROUP BY apn &lt;br /&gt; HAVING COUNT(*) &gt; 1; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Step 3 is impossible with what you posted.  What does "modified" mean &lt;br /&gt;and where is it in the tables?  I assume with the Properties, which &lt;br /&gt;means I need a history schema on it, too.  My mental image is that &lt;br /&gt;"modified" is going to involve the bedroom counts, kitchen appliances, &lt;br /&gt;roofing, etc. and NOT one column with a simple code in it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-1121087623017008907?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/1121087623017008907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=1121087623017008907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1121087623017008907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1121087623017008907'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/08/strange-query-options.html' title='A Strange Query Options'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2491876922204390438</id><published>2007-07-13T12:43:00.000-04:00</published><updated>2007-07-13T12:46:17.967-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boolean'/><category scheme='http://www.blogger.com/atom/ns#' term='Bit'/><title type='text'>Boolean computed column</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a column in my database I want to be a computed flag based on an &lt;br /&gt;active date.. the Flag column is called active.. &lt;br /&gt;&lt;br /&gt;basicall I want if the ActiveDate &lt;= getdate() (as in today is after the &lt;br /&gt;item was active) then the active flag is a bit 1, else its a bit 0... I &lt;br /&gt;tried this as a flat out &lt;= statement, got an error by SQL Managment &lt;br /&gt;studio... so how would this be done? thanks! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I have a column in my database I want to be a computed flag based on an active date.. the Flag column is called active..  basically I want if the ActiveDate &lt;= getdate() (as in today is after the item was active) then the active flag is a bit 1, else its a bit 0... &lt;br /&gt;I tried this as a flat out &lt;= statement, got an error by SQL &lt;br /&gt;Management studio... so how would this be done? &lt;&lt; &lt;br /&gt;&lt;br /&gt;This would be done by forgetting all the basic rules for programming &lt;br /&gt;in SQL :) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) We do not use the proprietary BIT data type that does not exist in &lt;br /&gt;Standard SQL &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) Flags are for assembly language programming and have no place in &lt;br /&gt;RDBMS; that is why SQL has no BOOLEAN data types &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) We do not store computed columns in a table.  Write a VIEW and &lt;br /&gt;learn to use CURRENT_TIMESTAMP instead of the old proprietary &lt;br /&gt;getdate() function call to get today's active data. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/c944e2a033c33b16/4ebd35a7997a8ae3#4ebd35a7997a8ae3"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2491876922204390438?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2491876922204390438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2491876922204390438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2491876922204390438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2491876922204390438'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/07/boolean-computed-column.html' title='Boolean computed column'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2909157076204503291</id><published>2007-07-13T12:39:00.000-04:00</published><updated>2007-07-13T12:40:48.146-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Views'/><title type='text'>SQL Views - embedded view work-a-rounds</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I've been asked to re-write a sql view. The view itself contains &lt;br /&gt;several calls to other views (embedded). Is there a way to get around &lt;br /&gt;using embedded views. I've written the same query up using temp. &lt;br /&gt;tables but obviously temp. tables can't be used in views? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there any special things I should be looking for? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I've been asked to re-write a sql view. The view itself contains several calls[sic: invocations?] to other views (embedded). Is there a way to get around using embedded views. I've written the same query up using temp tables but obviously temp. tables can't be used in views? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Nesting VIEWs is a good progrmming practice when it is done right. It &lt;br /&gt;can assure that nobody invents their own definition of something, like &lt;br /&gt;how we compute a tricky formula that can send us all to prison. &lt;br /&gt;&lt;br /&gt;Temp tables are a baaaaad idea.  The SQL Server model is in violation &lt;br /&gt;of ANSI/ISO and most everyone else's model of them.  They are usually &lt;br /&gt;a way to fake a "scratch tape" in a procedural solution, where each &lt;br /&gt;step passes the tape to the next step in a process; SQL is declarative &lt;br /&gt;and we want to write that way. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But the real point is that you never said *why* you want to re-write &lt;br /&gt;this unnamed VIEW.  Damn to give advise about anything without any &lt;br /&gt;kind of spec at all ..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2909157076204503291?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2909157076204503291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2909157076204503291' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2909157076204503291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2909157076204503291'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/07/sql-views-embedded-view-work-rounds.html' title='SQL Views - embedded view work-a-rounds'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2717429771547662122</id><published>2007-07-13T12:35:00.000-04:00</published><updated>2007-07-13T12:39:23.675-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Temp Tables'/><title type='text'>real world advise on temp tables please</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;a system with around 1500 users. a "bad" stored procedure that writes 3 &lt;br /&gt;#temp_tables. I notice system slow downs when more than 5 - 10 people run the &lt;br /&gt;SP at the same time. Is this to be expected. what are the real world &lt;br /&gt;expectancies of the temdb? &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; a "bad" stored procedure that writes 3 #temp_tables. I notice system slow downs when more than 5 - 10 people run the SP at the same time. Is this to be expected. what are the real world expectancies of the temdb? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Yes, it is expected.  The best solution is to re-write the procedure &lt;br /&gt;to use derived tables and subqueries. &lt;br /&gt;&lt;br /&gt;Besides being proprietary in both syntax and implementation the # temp &lt;br /&gt;tables are usually a sign of bad programming.  They are used as &lt;br /&gt;"scratch tapes" in a routine structured as if it were a 1950's mag &lt;br /&gt;tape batch; each step of a sequential process is written to a scratch &lt;br /&gt;tape (aka # temp table) to be passed to the following step. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Remember coupling and cohesion from that freshman S.E. course? &lt;br /&gt;Temporal coupling?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2717429771547662122?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2717429771547662122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2717429771547662122' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2717429771547662122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2717429771547662122'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/07/real-world-advise-on-temp-tables-please.html' title='real world advise on temp tables please'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3267249370587701547</id><published>2007-06-23T10:46:00.000-04:00</published><updated>2007-06-23T10:50:49.861-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Attribute Splitting'/><title type='text'>I have problem with union</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;use Sql Server 2000. I've structure like it:&lt;br /&gt;&lt;br /&gt;Create table T1(&lt;br /&gt;RID int primary key,&lt;br /&gt;A varchar(8),&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create table T2(&lt;br /&gt;RID int primary key,&lt;br /&gt;A varchar(8),&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To make easy to view, so I make a view like it&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create view VUni as&lt;br /&gt;Select RID, A From T1&lt;br /&gt;union&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Select RID, A From T2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, when I execute&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Select * From VUNI Where RID between 15 and 25&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So the process needs a lot of times alias Very Slow. How to make it best&lt;br /&gt;performance?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Oh yeach, it's other question, I want to select data from table which its&lt;br /&gt;name is name dimanically (variable)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;IF @YEAR=2000 Select * FROM T2000&lt;br /&gt;ELSE&lt;br /&gt;IF @YEAR=2001 Select * FROM T2001&lt;br /&gt;ELSE&lt;br /&gt;IF @YEAR=2002 Select * FROM T2002&lt;br /&gt;ELSE&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To make it compact, So how to the code?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next question, How to avoid error? I execute like it&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Select a/b from T2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;seldom the statement is error, because value of filed "a" is 0. I want if&lt;br /&gt;a/b is error calculation, so it give value 0 automatically. Can I do it?&lt;br /&gt;Without I ve to make a function? Or any function (built in) to handle it?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  I want to select data from table whose name is dynamic (variable) &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; IF @year=2000 SELECT  * FROM T2000 &lt;br /&gt; ELSE &lt;br /&gt; IF @year=2001 SELECT  * FROM T2001 &lt;br /&gt; ELSE &lt;br /&gt; IF @year=2002  SELECT * FROM T2002 &lt;br /&gt; ELSE &lt;br /&gt; ... &lt;br /&gt;&lt;&lt; &lt;br /&gt;&lt;br /&gt;This  design flaw is so bad it has a name, like a disease: "Attribute &lt;br /&gt;Splitting".  Instead of separate tables, you need one table with a &lt;br /&gt;"&lt;something&gt;_year" column in it.  You then use VIEWs or queries. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You probably also split an attribute in the first part of this &lt;br /&gt;posting, and are trying to fix it with a UNION [ALL] construct. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/f455e9c121ede776/6caf783a6ba2a0de?lnk=st&amp;q=&amp;amp;rnum=11#6caf783a6ba2a0de"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3267249370587701547?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3267249370587701547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3267249370587701547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3267249370587701547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3267249370587701547'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/i-have-problem-with-union.html' title='I have problem with union'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3874258448520508594</id><published>2007-06-23T10:39:00.000-04:00</published><updated>2007-06-23T10:45:45.219-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Calendar Table'/><title type='text'>Working days calendar in T-SQL</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;My company working days is from Monday to Friday.&lt;br /&gt;I would like to generate a result set which show all&lt;br /&gt;consecutive working days (Monday to Friday excluding the&lt;br /&gt;weekends) that is, for June 2007, it show me 1st, 4th, 5th,&lt;br /&gt;6th, 8th, 11th etc... until 29th (last working day of June). Is&lt;br /&gt;it possible to do this with T-SQL?My company working days is from Monday to Friday.&lt;br /&gt;I would like to generate a result set which show all&lt;br /&gt;consecutive working days (Monday to Friday excluding the&lt;br /&gt;weekends) that is, for June 2007, it show me 1st, 4th, 5th,&lt;br /&gt;6th, 8th, 11th etc... until 29th (last working day of June). Is&lt;br /&gt;it possible to do this with T-SQL?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Build a calendar table with one column for the calendar data and other&lt;br /&gt;columns to show whatever your business needs in the way of temporal&lt;br /&gt;information. Do not try to calculate holidays in SQL -- Easter alone&lt;br /&gt;requires too much math.&lt;br /&gt;&lt;br /&gt;CREATE TABLE Calendar&lt;br /&gt;(cal_date DATE NOT NULL PRIMARY KEY,&lt;br /&gt;fiscal_year INTEGER NOT NULL,&lt;br /&gt;fiscal_month INTEGER NOT NULL,&lt;br /&gt;week_in_year INTEGER NOT NULL, -- SQL server is not ISO standard&lt;br /&gt;holiday_type INTEGER NOT NULL&lt;br /&gt;CHECK(holiday_type IN ( ..), --&lt;br /&gt;day_in_year INTEGER NOT NULL,&lt;br /&gt;julian_business_day INTEGER NOT NULL,&lt;br /&gt;...);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Julian business day is a good trick. Number the days from&lt;br /&gt;whenever your calendar starts and repeat a number for a weekend or&lt;br /&gt;company holiday.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A calendar table for US Secular holidays can be built from the data at&lt;br /&gt;this website, so you will get the three-day weekends:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.smart.net/~mmontes/ushols.html" target="_blank" rel="nofollow"&gt;http://www.smart.net/~mmontes/ushols.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Time zones with fractional hour displacements &lt;a href="http://www.timeanddate.com/worldclock/city.html?n=246" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=246&lt;/a&gt; &lt;a href="http://www.timeanddate.com/worldclock/city.html?n=176" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=176&lt;/a&gt; &lt;a href="http://www.timeanddate.com/worldclock/city.html?n=5" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=5&lt;/a&gt; &lt;a href="http://www.timeanddate.com/worldclock/city.html?n=54" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=54&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But the STRANGE ones are:&lt;br /&gt;&lt;a href="http://www.timeanddate.com/worldclock/city.html?n=63" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=63&lt;/a&gt; &lt;a href="http://www.timeanddate.com/worldclock/city.html?n=5" target="_blank" rel="nofollow"&gt;http://www.timeanddate.com/worldclock/city.html?n=5&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/26046e2cfb653d41/049e9e75e3359eae#049e9e75e3359eae"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3874258448520508594?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3874258448520508594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3874258448520508594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3874258448520508594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3874258448520508594'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/working-days-calendar-in-t-sql.html' title='Working days calendar in T-SQL'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2631679607052769268</id><published>2007-06-16T09:07:00.000-04:00</published><updated>2007-06-16T09:10:47.753-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dates'/><category scheme='http://www.blogger.com/atom/ns#' term='group by'/><title type='text'>group by datetime</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am baffled by this query and can use a little help pls! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;query count for each Monday of the week in the last few months between 9 pm &lt;br /&gt;and 1 am.  I know I can use datepart() but can't figure out how to query &lt;br /&gt;between 9pm and 1am. Thanks. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I am baffled by this query and can use a little help pls! &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. Why are you so rude? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; query count for each Monday of the week in the last few month between 9 pm [sic: 11:00:00 Hrs] and 1 am [sic: 01:00:00 the next day??].  I know I can use DATEPART() but can't figure out how to query between 9 pm [sic] and 1 am [sic]. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You really have no idea how time works!!  What the hell is that AM and &lt;br /&gt;PM crap?  You never heard of ISO-8601 Standards and UTC??? &lt;br /&gt;&lt;br /&gt;What you do is set up a table of temporal ranges with upper and lower &lt;br /&gt;limits with TIMESTAMP limits and join to it.  Hey, you spit on us by &lt;br /&gt;not posting DDL, why should we post DDL and data for you? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your unit of measurement is wrong and you are getting screwed up.  But &lt;br /&gt;your invisible DDL tells us nothing!! &lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/c59c7d7dc861d441/13385cd00350c024#13385cd00350c024"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2631679607052769268?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2631679607052769268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2631679607052769268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2631679607052769268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2631679607052769268'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/group-by-datetime.html' title='group by datetime'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3577857612204199980</id><published>2007-06-16T09:03:00.000-04:00</published><updated>2007-06-16T09:07:24.311-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Update'/><title type='text'>Updating based on values of two records</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm sure this is obvious, but for some reason, I can't get my hands &lt;br /&gt;around the solution.  I have a table like this: &lt;br /&gt;&lt;br /&gt;Account    CalYear    CalMonth    Amount &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Comm        2006          12              80 &lt;br /&gt;Comm        2007          01              100 &lt;br /&gt;Comm        2007          02              125 &lt;br /&gt;Incr            2007          01               21 &lt;br /&gt;Incr            2007          02               28 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to update the incr account so it shows the correct difference &lt;br /&gt;between the previous month, the change basically.  Corrected it would &lt;br /&gt;look like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Account    CalYear    CalMonth    Amount &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Comm        2006          12              80 &lt;br /&gt;Comm        2007          01              100 &lt;br /&gt;Comm        2007          02              125 &lt;br /&gt;Incr            2007          01               20 &lt;br /&gt;Incr            2007          02               25 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have a table like this: &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why do you spit on us and want us to do your homework/job for you? &lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why did you invent your own two column data types that avoid the &lt;br /&gt;temporal data types? Have you ever read the ISO-8601 rules for &lt;br /&gt;temporal data? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE StinkingFoobar  -- until we get a real name &lt;br /&gt;(acct_type CHAR(4) NOT NULL, &lt;br /&gt; start_date DATETIME NOT NULL, &lt;br /&gt; end_date DATETIME NOT NULL, &lt;br /&gt; CHECK (start_date &lt; end_date), &lt;br /&gt; squid_amt INTEGER NOT NULL,  -- read ISO-11179 before you program &lt;br /&gt;again!! &lt;br /&gt; PRIMARY KEY (acct_type, start_date) &lt;br /&gt;); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Did I guess right?? Gee, wish you had helped!! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I want to update the incr account so it shows the correct difference between the previous month &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No. That is soooooo non-RDBMS!!   This is a computed value and needs &lt;br /&gt;to be done in a VIEW using the OLAP functions.  RTFM. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/37eead51099cacb5/35b09e8c33bde417#35b09e8c33bde417"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3577857612204199980?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3577857612204199980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3577857612204199980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3577857612204199980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3577857612204199980'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/updating-based-on-values-of-two-records.html' title='Updating based on values of two records'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-5776483331469050307</id><published>2007-06-16T09:00:00.000-04:00</published><updated>2007-06-16T09:01:59.277-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sets'/><category scheme='http://www.blogger.com/atom/ns#' term='Update'/><title type='text'>newbie question on update</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a clients table which consists of, among other things, a column &lt;br /&gt;named source. &lt;br /&gt;&lt;br /&gt;I have a second table, sources, with two columns - client_id and source. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The are fewer rows in sources than in clients. I am trying to update &lt;br /&gt;clients.source with sources.source without affecting the clients that &lt;br /&gt;do not have a corresponding row in sources. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My first try was update clients set clients.source = sources.source &lt;br /&gt;where clients.client_id = sources.client_id &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But I ended up with nulls in the clients.source column for rows in &lt;br /&gt;which there was no row in sources. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am guessing that I need to involve a join somehow, but I am having a &lt;br /&gt;very hard time not thinking procedurally, and just don't "get" it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've been looking at Join examples, but anything non-trivial just &lt;br /&gt;baffles me. Would someone be so kind as to explain how to do what I'm &lt;br /&gt;trying to do? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I am finding it difficult to think in terms of sets and 'simultaneous'  actions. I keep wanting to solve these things procedurally. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It takes about a year to have the revelation :)  My next book will &lt;br /&gt;deal with thinking in sets.  Hey, remember how weird recursion was? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/comp.databases/browse_thread/thread/8e8a8e2dbc0e5f0a/f817004a37ee5279#f817004a37ee5279"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-5776483331469050307?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/5776483331469050307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=5776483331469050307' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5776483331469050307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5776483331469050307'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/newbie-question-on-update.html' title='newbie question on update'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4041683874566943401</id><published>2007-06-14T08:55:00.000-04:00</published><updated>2007-06-14T08:56:37.339-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='COALESCE'/><title type='text'>Question regarding multiple data sources and coalesce</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I inherited a db that is pulling data from 5 different sources and &lt;br /&gt;storing them in 5 different tables.  The tables all have the same &lt;br /&gt;basic data, minor differences based on source.  The company currently &lt;br /&gt;creates a "summary" table by joining the 5 source tables and using &lt;br /&gt;coalesce( ) to display data from preferred data sources if it is &lt;br /&gt;available from there. &lt;br /&gt;&lt;br /&gt;I've been asked to present an alternate schema.  My first thought was &lt;br /&gt;to normalize the 5 tables into 1 with a source andI could just include &lt;br /&gt;the source in the ORDER BY of queries to get the preferred source. &lt;br /&gt;But then I thought since each source could have 30Million rows maybe I &lt;br /&gt;would loose performance over the existing schema.  So, could somebody &lt;br /&gt;point me towards a reference source that may cover this type of &lt;br /&gt;topic?  Of course, any opinions (on this issue) would be appreciated &lt;br /&gt;as well. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I've been asked to present an alternate schema.  My first thought was to normalize the 5 tables into 1 with a source and I could just include the source in the ORDER BY of queries to get the preferred source. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Something ike this?  Cram all the data that you have into staging &lt;br /&gt;table &lt;br /&gt;&lt;br /&gt;CREATE TABLE Foobar &lt;br /&gt;(foo_key INTEGER NOT NULL, &lt;br /&gt; source_nbr  INTEGER NOT NULL &lt;br /&gt;  CHECK (source_nbr BETWEEN 1 AND 5), &lt;br /&gt;PRIMARY KEY (foo_key, source_nbr), &lt;br /&gt;etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Assuming sources are ranks from 1 to 5, pull out the most trusted for &lt;br /&gt;each key &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT foo_key, etc. &lt;br /&gt;  FROM Foobar AS F1 &lt;br /&gt;WHERE source_nbr = &lt;br /&gt;   (SELECT MIN(source_nbr) &lt;br /&gt;      FROM Foobar AS F2 &lt;br /&gt;  WHERE F1.foo_key = F2.foo_key); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is the best we can do without more specs. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/fc6bbcdc62e4c0c0/40ea80d1ee6375b9#40ea80d1ee6375b9"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4041683874566943401?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4041683874566943401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4041683874566943401' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4041683874566943401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4041683874566943401'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/question-regarding-multiple-data.html' title='Question regarding multiple data sources and coalesce'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2602186170073215294</id><published>2007-06-14T08:52:00.000-04:00</published><updated>2007-06-14T08:54:47.307-04:00</updated><title type='text'>Need urgent help on a QUERY</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Given: &lt;br /&gt;&lt;br /&gt;SELECT  STATE_ID &lt;br /&gt;FROM     GROUP_STATE &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;STATE_ID &lt;br /&gt;---------------- &lt;br /&gt;10 &lt;br /&gt;15 &lt;br /&gt;16 &lt;br /&gt;17 &lt;br /&gt;18 &lt;br /&gt;19 &lt;br /&gt;20 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT GROUP_ID &lt;br /&gt;FROM GROUP &lt;br /&gt;WHERE  GROUP_ID  NOT IN (SELECT DISTINCT GROUP_ID FROM GROUP_STATE) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GROUP_ID &lt;br /&gt;--------------- &lt;br /&gt;1 &lt;br /&gt;2 &lt;br /&gt;16 &lt;br /&gt;5 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need a query that would look like: &lt;br /&gt;GROUP_ID                 STATE_ID &lt;br /&gt;---------------                  ---------------- &lt;br /&gt;1                              10 &lt;br /&gt;1                              15 &lt;br /&gt;1                              16 &lt;br /&gt;1                              17 &lt;br /&gt;1                              18 &lt;br /&gt;1                              19 &lt;br /&gt;1                              20 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2                              10 &lt;br /&gt;2                              15 &lt;br /&gt;2                              16 &lt;br /&gt;2                              17 &lt;br /&gt;2                              18 &lt;br /&gt;2                              19 &lt;br /&gt;2                              20 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ETC.... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;SELECT GS.state_id,  G.group_id &lt;br /&gt;FROM ( SELECT  state_id  FROM  GroupStates AS GS &lt;br /&gt; CROSS JOIN &lt;br /&gt; SELECT group_id FROM Groups &lt;br /&gt; WHERE  group_id   &lt;br /&gt;     NOT IN (SELECT DISTINCT group_id  FROM  GroupStates) &lt;br /&gt;  AS G); &lt;br /&gt;&lt;br /&gt;Do not use reserved words for data element names.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/aec8c38d8f281876/a7e58b73b8be2487#a7e58b73b8be2487"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2602186170073215294?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2602186170073215294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2602186170073215294' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2602186170073215294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2602186170073215294'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/need-urgent-help-on-query.html' title='Need urgent help on a QUERY'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3017612512004085977</id><published>2007-06-14T08:50:00.000-04:00</published><updated>2007-06-14T08:52:28.303-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Order'/><title type='text'>changing order of records</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;hi, i've got a problem. i need to change order of records in my table . here &lt;br /&gt;is the table &lt;br /&gt;&lt;br /&gt;id  forumname &lt;br /&gt;---------------- &lt;br /&gt;1  test1 &lt;br /&gt;2  test2 &lt;br /&gt;3  test3 &lt;br /&gt;4  test4 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;i need to write  code that can move nay record up or down without changing &lt;br /&gt;id of forumname. i thought about another column called order &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;id  forumname order &lt;br /&gt;--------------------- &lt;br /&gt;1  test1            1 &lt;br /&gt;2  test2            2 &lt;br /&gt;3  test3            3 &lt;br /&gt;4  test4            4 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;but couldnt figureout how to change that order column. any one got an idea? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Here is an old "cut &amp; paste" for this problem: Given a motorpool with &lt;br /&gt;numbered parking spaces, you want to move the automobiles around. &lt;br /&gt;CREATE TABLE Motorpool &lt;br /&gt;(parking_space INTEGER NOT NULL PRIMARY KEY &lt;br /&gt;   CHECK (parking_space &gt; 0), &lt;br /&gt; vin CHAR(17) NOT NULL); &lt;br /&gt;&lt;br /&gt;Re-arrange the display order based on the parking_space column: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE SwapVehicles (@old_parking_space INTEGER, &lt;br /&gt;@new_parking_space INTEGER) &lt;br /&gt;AS &lt;br /&gt;UPDATE Motorpool &lt;br /&gt;   SET parking_space &lt;br /&gt;       = CASE parking_space &lt;br /&gt;         WHEN @old_parking_space &lt;br /&gt;         THEN @new_parking_space &lt;br /&gt;         ELSE parking_space + SIGN(@old_parking_space - @new_pos) &lt;br /&gt;         END &lt;br /&gt; WHERE parking_space BETWEEN @old_parking_space AND &lt;br /&gt;@new_parking_space &lt;br /&gt;    OR parking_space BETWEEN @new_parking_space AND &lt;br /&gt;@old_parking_space; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you want to drop a few rows, remember to close the gaps with &lt;br /&gt;this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE CloseMotorpoolGaps() &lt;br /&gt;AS &lt;br /&gt;UPDATE Motorpool &lt;br /&gt;   SET parking_space &lt;br /&gt;       = (SELECT COUNT (M1.parking_space) &lt;br /&gt;            FROM Motorpool AS M1 &lt;br /&gt;           WHERE M1.parking_space &lt;= Motorpool.parking_space); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/8cb1fd9bd620671e/acf5c792e9ab2f85#acf5c792e9ab2f85"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3017612512004085977?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3017612512004085977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3017612512004085977' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3017612512004085977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3017612512004085977'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/changing-order-of-records.html' title='changing order of records'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-5483234354299001529</id><published>2007-06-13T06:59:00.000-04:00</published><updated>2007-06-13T07:03:15.234-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Constraint'/><category scheme='http://www.blogger.com/atom/ns#' term='Identity'/><title type='text'>self-referencing constraint with identity column?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a table that requires to have a self-referencing constraint to enforce &lt;br /&gt;a parent-child type of relationship: &lt;br /&gt;&lt;br /&gt;ID (identity column) &lt;br /&gt;ParentID (INT column that references the ID column). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To determine if I'm at the top-level of of the relationship, I was going to &lt;br /&gt;leave the ParentID null, otherwise it must be a value of another ID column in &lt;br /&gt;the table which indicates its child of another. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, can you have it so you don't use NULL to indicate this and instead &lt;br /&gt;set ID and ParentID equal to the same value and still use the IDENTITY column? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So on a INSERT (i.e the IDENTITY would generate 25, so I'd like to set the &lt;br /&gt;ParentID to 25 as well).  This would was causing FK violation and I was &lt;br /&gt;wondering if there is a way around it using an insert trigger? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have a table that requires to have a self-referencing constraint to enforce a parent-child type of relationship: &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No it is not required at all.  Look up the Nested Sets model for trees &lt;br /&gt;and hierarchies. You will find the constraitns are much easier and the &lt;br /&gt;code will run1-2 orders of magnitude faster than recursive path &lt;br /&gt;traversals. &lt;br /&gt;&lt;br /&gt;Also, never use IDENTITY in an RDBMS; find a valid relational key &lt;br /&gt;instead. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/46648efa3dc2a6bc/5b387312408828f3#5b387312408828f3"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-5483234354299001529?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/5483234354299001529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=5483234354299001529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5483234354299001529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5483234354299001529'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/self-referencing-constraint-with.html' title='self-referencing constraint with identity column?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-11874134493303659</id><published>2007-06-12T06:13:00.000-04:00</published><updated>2007-06-12T06:15:44.396-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adjacency List Model'/><category scheme='http://www.blogger.com/atom/ns#' term='Nested Sets Model'/><category scheme='http://www.blogger.com/atom/ns#' term='Database Design'/><title type='text'>Database Design Question</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm fairly new to database design, having only really worked with &lt;br /&gt;existing tables etc in the past. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Simple question this really........... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In a users table, is it wise to have a ManagerID column that is &lt;br /&gt;effectively pointing to another user in the same table, with the &lt;br /&gt;theory being that if that person is top dog, they will just have a &lt;br /&gt;null entry in ManagerID. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I will check for circular references before entering the data. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there a better way of storing the data, or is this the only way? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Is there a better way of storing the data, or is this the only way? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Get a copy of &lt;a href="http://www.amazon.com/exec/obidos/ASIN/1558609202/sql08-20/102-5735017-0910517?%5Fencoding=UTF8&amp;camp=1789&amp;link%5Fcode=xm2"&gt;TREES &amp; HIERARCHIES IN SQL&lt;/a&gt; for several different ways to &lt;br /&gt;do an organizational chart.  What you have is thd adjacency list &lt;br /&gt;model; look up the nested sets model. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/comp.databases.ms-sqlserver/browse_thread/thread/44f56696d9e6a1d2/f6e06072f19b2f70#f6e06072f19b2f70"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-11874134493303659?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/11874134493303659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=11874134493303659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/11874134493303659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/11874134493303659'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/database-design-question.html' title='Database Design Question'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-774871438509557961</id><published>2007-06-12T06:09:00.000-04:00</published><updated>2007-06-12T06:11:03.273-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Soundex'/><category scheme='http://www.blogger.com/atom/ns#' term='Duplicates'/><title type='text'>Using Soundex to identify possible duplicates</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;In a table that has person forename and surname, is it possible to use &lt;br /&gt;soundex to identify for every row in the table what similar matches &lt;br /&gt;there are in the same table? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; is it possible to use Soundex to identify for every row in the table what similar matches there are in the same table?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Don't do it. Name handling is an ugly problem and if you have to do &lt;br /&gt;this on a regular basis get a package designed for this kind of work. &lt;br /&gt;Some companies are Group 1 Software, SSA (used to have a great booklet &lt;br /&gt;on this topic), Melissa Data Corporation and Promark Software Inc. &lt;br /&gt;&lt;br /&gt;Their software handles mailing lists and you can get a review copy &lt;br /&gt;from Melissa Data. They do not choke on names like "John Paul van der &lt;br /&gt;Poon" and worse. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/f217bf9ee2a28773/6af67bc503fc785f#6af67bc503fc785f"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-774871438509557961?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/774871438509557961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=774871438509557961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/774871438509557961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/774871438509557961'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/using-soundex-to-identify-possible.html' title='Using Soundex to identify possible duplicates'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4938161998413030290</id><published>2007-06-12T06:06:00.000-04:00</published><updated>2007-06-12T06:08:50.327-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Union'/><title type='text'>giving one union preference</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Let say I have a query with the following structure: &lt;br /&gt;&lt;br /&gt;Select name, mdate, kdate &lt;br /&gt;from table1 a &lt;br /&gt;inner join ( &lt;br /&gt;              select name, mdate &lt;br /&gt;              from table2 b &lt;br /&gt;              where a.id = b.id &lt;br /&gt;              and mdate &gt;= kdate &lt;br /&gt;              union &lt;br /&gt;              select name, mdate &lt;br /&gt;              from table3 c &lt;br /&gt;              where a.id = c.id &lt;br /&gt;              and mdate &gt;= kdate &lt;br /&gt;              ) mindate &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When the select mdate from the inner join union (mindate) returns the &lt;br /&gt;same mdate for table b and c, I want to give preference to the c.mdate &lt;br /&gt;and so c.name. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there a way to do this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; When the select mdate from the inner join union (mindate) returns the same mdate for table b and c, I want to give preference to the c.mdate and so c.name. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This question makes no sense.  The poorly named derived table, &lt;br /&gt;Mindate, acts as if it is materialized and you no longer have access &lt;br /&gt;to tables B and C.  It is like asking to see the eggs after the cake &lt;br /&gt;has been baked. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/9011ed4f87d8bcdb/259d972a327d9139#259d972a327d9139"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4938161998413030290?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4938161998413030290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4938161998413030290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4938161998413030290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4938161998413030290'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/giving-one-union-preference.html' title='giving one union preference'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-7093397947008173100</id><published>2007-06-12T06:04:00.000-04:00</published><updated>2007-06-12T06:06:07.919-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Calendar Table'/><category scheme='http://www.blogger.com/atom/ns#' term='Holidays'/><title type='text'>Help writing query to return data if there are 4 consecutive holidays</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; I need to write a query that returns data if an employee has taken four or &lt;br /&gt;more consecutive holidays. I need to get the startdate and the employee name. &lt;br /&gt;The employee works either a 4X10..or an 8X5 shift... &lt;br /&gt;Also, the employee need not have an off only on Sat and Sun...Some of them &lt;br /&gt;work on the weekends and have an off during the weekdays. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Also, I need to take into account the days employee is off (eg.Sat and Sun). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So if an employee is out Mon, Tues, Wed, Thu it shows that employee or if &lt;br /&gt;the employee is out on Thu, Fri, Mon, Tues it also shows that employee... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can anyone assist! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Use a Calendar table which has the work days Julianized (consecutively &lt;br /&gt;numbered).  Google this newsgroup for examples.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/7d44e4868787efa7/27e3fcb908395c7a#27e3fcb908395c7a"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7093397947008173100?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7093397947008173100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7093397947008173100' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7093397947008173100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7093397947008173100'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/help-writing-query-to-return-data-if.html' title='Help writing query to return data if there are 4 consecutive holidays'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-8860723703495126100</id><published>2007-06-12T06:00:00.000-04:00</published><updated>2007-06-12T06:03:46.454-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Formatting Data'/><title type='text'>add blank row between groups of rows to separate them?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I want to add a blank row between groups of rows to separate them.   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select * from tbl1 where fname in ('Bill', 'tom', 'sam') &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;returns &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bill, 1, 2, 3 &lt;br /&gt;bill  4, 5, 6 &lt;br /&gt;tom, 1, 2, 3 &lt;br /&gt;tom, 4, 5, 6 &lt;br /&gt;sam, 1, 2, 3 &lt;br /&gt;sam, 4, 5, 6 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to return this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bill, 1, 2, 3 &lt;br /&gt;bill  4, 5, 6 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tom, 1, 2, 3 &lt;br /&gt;tom, 4, 5, 6 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;sam, 1, 2, 3 &lt;br /&gt;sam, 4, 5, 6 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How can I perform this type of operation with tsql? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; How can I perform this type of operation with tsql? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why are you formatting data in the back end?  The basic principle of a &lt;br /&gt;tiered architecture is that display is done in the front end and never &lt;br /&gt;in the back end.  This a more basic programming principle than just &lt;br /&gt;SQL and RDBMS. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/4b3eede705c72b88/90c694dc9d8dcc51#90c694dc9d8dcc51"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-8860723703495126100?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/8860723703495126100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=8860723703495126100' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8860723703495126100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8860723703495126100'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/add-blank-row-between-groups-of-rows-to.html' title='add blank row between groups of rows to separate them?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6793597761382977482</id><published>2007-06-11T09:18:00.000-04:00</published><updated>2007-06-11T09:19:55.045-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISO-8601'/><title type='text'>Calc minutes between days</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am using DATEDIFF('n',EndTime, StartTime) to return minutes between 2 &lt;br /&gt;datetime columns.  The problem is that when the StartTime is 23:00:00 PM and &lt;br /&gt;EndTime is 07:00:00 AM I get a negative # of minutes.  How can get 480 &lt;br /&gt;minutes from this calculation.  Note the 23:00:00 is yesterday and the &lt;br /&gt;07:00:00 is today.  Thanks&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; OK, but I'm not storing the date portion so it thinks both dates are 12/30/1899.  Do I need a CASE statement to check for 1st time  2nd time? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No, you need to learn to do it right and not look for kludges in &lt;br /&gt;newsgroups.  Oh, you will get the kludges, as you have seen, but then &lt;br /&gt;your code will become a convoluted mess over time, queries cannot use &lt;br /&gt;indexes, portability is destroyed, etc. &lt;br /&gt;&lt;br /&gt;It would also help if you had learned to use ISO-8601 temporal &lt;br /&gt;formats, too (i.e '1899-12-30').  That would have lead you to study &lt;br /&gt;the ISO temporal model.  A proper data model will use DATETIME data &lt;br /&gt;types and model events as having durations.  Get a free copy of Rick &lt;br /&gt;Snodgrass book in PDF from the University of Arizona website and spent &lt;br /&gt;a week with.  There is also a ton of free code you can download.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6793597761382977482?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6793597761382977482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6793597761382977482' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6793597761382977482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6793597761382977482'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/calc-minutes-between-days.html' title='Calc minutes between days'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-5021881299173706329</id><published>2007-06-11T09:12:00.000-04:00</published><updated>2007-06-11T09:15:36.560-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISO-11179'/><title type='text'>Get info from multiple tables. Join problem? Options</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;The Stored Procedure below returns article attributes for my articles &lt;br /&gt;(tblArticleAttribute). This works fine IF NOT tblArticleAttribute.Content is &lt;br /&gt;empty, then it returns all templatedefinitions with the Content. But, if the &lt;br /&gt;Content is empty, it also has to return all template definitions, but with &lt;br /&gt;the content fields empty (now it returns nothing). This is because I bind &lt;br /&gt;this information to a dynamic form, and if (example) the title or ingress is &lt;br /&gt;empty the textfields (definitions) should be shown with no text. Then the &lt;br /&gt;user can fill inn text an save it. &lt;br /&gt;&lt;br /&gt;---------------------------------- &lt;br /&gt;Here is the SQL: &lt;br /&gt;---------------------------------- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT tblTemplateDefinition.[Name] as TemplateDefinitionName, &lt;br /&gt;tblTemplateDefinition.HelpText as TemplateDefinitionHelpText, &lt;br /&gt;tblArticleAttribute.[Content], tblArticle.Id AS ArticleId, &lt;br /&gt;tblTemplateDefinition.Id AS TemplateDefinitionId &lt;br /&gt;FROM tblTemplateDefinition &lt;br /&gt;LEFT OUTER JOIN tblArticleAttribute ON tblTemplateDefinition.Id = &lt;br /&gt;tblArticleAttribute.TemplateDefinitionId &lt;br /&gt;INNER JOIN tblArticle ON tblArticleAttribute.ArticleId= tblArticle.Id &lt;br /&gt;WHERE  tblArticle.Id = @ArticleId &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;---------------------------------- &lt;br /&gt;Here is the tables: &lt;br /&gt;---------------------------------- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblArticle: &lt;br /&gt;id | Name &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblArticleAttribute &lt;br /&gt;TemplateDefinitionId | ArticleId | Content &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblTemplate &lt;br /&gt;Id | Name &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblTemplateDefinition &lt;br /&gt;Id | TemplateId | TemplateDefinitionId |Name | HelpText &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;You might want to read any basic book on data modeling.  You seem to &lt;br /&gt;have multiple names for the same data element, based on where it &lt;br /&gt;appears.  And you have a universal, magical "id" column in all the &lt;br /&gt;pseudo-code you did give us. You also violate ISO-11179 naming rules. &lt;br /&gt;My guess as to what you meant to post if you knew how would be &lt;br /&gt;something like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Articles: &lt;br /&gt;(article_id INTEGER NOT NULL PRIMARY KEY, -- needs work &lt;br /&gt; article_title VARCHAR(150) NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have no idea which carefully researched industry standard you are &lt;br /&gt;using the article identifier.  But at least I know it is not an &lt;br /&gt;IDENTITY column -- that would be soooo non-relational. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why did you use a singular name for the table?  Do you really have &lt;br /&gt;only one article.  Why did you put that silly "tbl-" prefix on the &lt;br /&gt;table names?  Just to mess up the data dictionary, or because you are &lt;br /&gt;an OO programmer who has not learned RDBMS yet? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE ArticleAttributes &lt;br /&gt;(template_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; article_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Articles(article_id) &lt;br /&gt;   ON UPDATE CASCADE &lt;br /&gt;   ON DELETE CASCADE, &lt;br /&gt; article_content VARCHAR(255) NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We would never store attributes in a schema; that would mix data and &lt;br /&gt;metadata.  What about the templates?  Why is the definition of a &lt;br /&gt;template not an attribute of a template?  Why it is an entity with its &lt;br /&gt;own table? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also note that you need DRI actions, constraints, etc. to make this &lt;br /&gt;work. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can make a lot of assumptions about the magical universal names and &lt;br /&gt;how they are related (is the magical "id" actually article_id, &lt;br /&gt;template_id, template_definition_id, template_id, or a hundred other &lt;br /&gt;possible things?) and the cardinality of the relationships, etc., but &lt;br /&gt;based on decades of cleaning up bad schemas, you need more than a &lt;br /&gt;sample query with an OUTER JOIN. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can you explain your problem better?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-5021881299173706329?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/5021881299173706329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=5021881299173706329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5021881299173706329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5021881299173706329'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/get-info-from-multiple-tables-join.html' title='Get info from multiple tables. Join problem? Options'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2925853962612463482</id><published>2007-06-07T11:50:00.000-04:00</published><updated>2007-06-12T06:17:54.495-04:00</updated><title type='text'>Maximum number of tables (260) exceeded</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Hi! I receive the referenced message when i run a view I created in SQL2005&lt;br /&gt;in a SQL2000 install of the same database. Basically it is a union query with&lt;br /&gt;about 9 individual select queries. I am sure this has something to do with a&lt;br /&gt;lack of efficiency in my query structure but I am confounded that it runs in&lt;br /&gt;SQL2005 and not in SQL2000. Any suggestions? Thanks in avance for any help&lt;br /&gt;you can offer...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I am confounded that it runs in SQL2005 and not in SQL2000. Any suggestions?&lt;br /&gt;&lt;br /&gt;Why not just write better code?  Seriously, after all my decades (NOT &lt;br /&gt;years) with SQL, I cannot imagine anything properly designed that &lt;br /&gt;would break the limit. &lt;br /&gt;&lt;br /&gt;Remember the human interface part of the first SE course you had &lt;br /&gt;before you were allowed to production data?  5 to 7 levels is all a &lt;br /&gt;human being can maintain.  Duh. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Find the moron who nested things this deep and kill him.  Then re- &lt;br /&gt;write EVERYTHING he wrote and re-write it.  Do a Wikipeida on &lt;br /&gt;"spaghetti code" versus "lasagna code" for some of the issues. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/3564fe02d9deb6bf/8b715a9044588214#8b715a9044588214"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2925853962612463482?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2925853962612463482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2925853962612463482' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2925853962612463482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2925853962612463482'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/maximum-number-of-tables-260-exceeded.html' title='Maximum number of tables (260) exceeded'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-8610991687356120475</id><published>2007-06-04T05:44:00.000-04:00</published><updated>2007-06-04T05:49:10.597-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>db table design question</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;We have an application which has its settings stored in a database&lt;br /&gt;(SQL Server 2000)&lt;br /&gt;&lt;br /&gt;We have (strong) disagrements on the best way to store these values,&lt;br /&gt;and I am looking for advice on doing this.&lt;br /&gt;Most of the values are not used by the stored procedures, just the&lt;br /&gt;applications running on the clients PC. The data rarely changes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Developer #1 wants many tables with many columns. This gives the&lt;br /&gt;ability to strongly type each variable. Each table would have only&lt;br /&gt;one row. He believes this to be faster in retrieving the data.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Developer #2 wants one table with a Key column and a Value column.&lt;br /&gt;This table would have many rows. The application would be&lt;br /&gt;responsible&lt;br /&gt;for detecting invalid datatype in the value. He believes this to be&lt;br /&gt;a&lt;br /&gt;more efficent use of the database, and easier to maintain.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So - what do you think? Are there any advantages or problems with&lt;br /&gt;either approach?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Use #1. The other way is called a OTLT ("One True Lookup Table") or&lt;br /&gt;MUCK ("Massively Unified Code Keys") in the literature. It is&lt;br /&gt;incredibly bad design. Here is a cut and paste from one of my books&lt;br /&gt;on Constants tables&lt;br /&gt;&lt;br /&gt;04.02. Constants Table&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you configure a system, you might want to have a way to set and&lt;br /&gt;keep constants in the schema. One method for doing this is to have a&lt;br /&gt;one-row table that can be set with default values at the start, and&lt;br /&gt;then updated only by someone with administrative privileges.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Constants&lt;br /&gt;(lock CHAR(1) DEFAULT 'X'&lt;br /&gt;NOT NULL PRIMARY KEY&lt;br /&gt;CHECK (lock = 'X'),&lt;br /&gt;pi FLOAT DEFAULT 3.142592653 NOT NULL,&lt;br /&gt;e FLOAT DEFAULT 2.71828182 NOT NULL,&lt;br /&gt;phi FLOAT DEFAULT 1.6180339887 NOT NULL,&lt;br /&gt;..);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To initialize the row, execute this statement.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Constants VALUES DEFAULTS;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Most SQL programmers do not know about the VALUES DEFAULTS option in&lt;br /&gt;the INSERT INTO statement. The lock column assures there is only one&lt;br /&gt;row and the DEFAULT values load the initial values. These defaults&lt;br /&gt;can include the current user and current timestamp, as well as numeric&lt;br /&gt;and character constant values.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Another version of this idea that does not allow for any updates is a&lt;br /&gt;VIEW defined with a table constructor. [[not in SQL Server yet!]]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW Constants (pi, e, phi, ..)&lt;br /&gt;AS VALUES (CAST 3.142592653 AS FLOAT),&lt;br /&gt;(CAST 2.71828182 AS FLOAT),&lt;br /&gt;(CAST 1.6180339887 AS FLOAT),&lt;br /&gt;..;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please notice that you have to use a CAST() operators to assure that&lt;br /&gt;the data types are correct. This is not a problem with INTEGER&lt;br /&gt;values, but can be if you wanted DOUBLE PRECISION and got a default of&lt;br /&gt;DECIMAL(s, p) or FLOAT.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[[ a little bit later in the chapter..]]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;OTLT or MUCK Table Problems&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I think that Paul Keister was the first person to coin the phrase&lt;br /&gt;"OTLT" (One True Look-up Table) for a common SQL programming technique&lt;br /&gt;that is popular with Newbies. Don Peterson (&lt;a href="http://www.SQLServerCentral.com"&gt;www.SQLServerCentral.com&lt;/a&gt;)&lt;br /&gt;gave the same technique the name "Massively Unified Code-Key" or MUCK&lt;br /&gt;tables in one of his articles.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The technique crops up time and time again, but I'll give him credit&lt;br /&gt;as the first writer to give it a name. Simply put, the idea is to&lt;br /&gt;have one table to do all of the code look-ups in the schema. It&lt;br /&gt;usually looks like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Look-ups&lt;br /&gt;(code_type CHAR(10) NOT NULL,&lt;br /&gt;code_value VARCHAR(255) NOT NULL, -- notice size!&lt;br /&gt;code_description VARCHAR(255) NOT NULL, -- notice size!&lt;br /&gt;PRIMARY KEY (code_value, code_type));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So if we have Dewey Decimal Classification (library codes), ICD&lt;br /&gt;(International Classification of Diseases), and two-letter ISO-3166&lt;br /&gt;country codes in the schema, we have them all in one, honking big&lt;br /&gt;table.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let's start with the problems in the DDL and then look at the awful&lt;br /&gt;queries you have to write (or hide in VIEWs). So we need to go back&lt;br /&gt;to the original DDL and add a CHECK() constraint on the code_type&lt;br /&gt;column. Otherwise, we might "invent" a new encoding system by&lt;br /&gt;typographical error.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Dewey Decimal and ICD codes are digits and have the same format --&lt;br /&gt;three digits, a decimal point and more digits (usually three); the&lt;br /&gt;ISO-3166 is alphabetic. Oops, need another CHECK constraint that will&lt;br /&gt;look at the code_type and make sure that the string is in the right&lt;br /&gt;format. Now the table looks something like this, if anyone attempted&lt;br /&gt;to do it right, which is not usually the case:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE OTLT&lt;br /&gt;(code_type CHAR(10) NOT NULL&lt;br /&gt;CHECK(code_type IN ('DDC','ICD','ISO3166', ..),&lt;br /&gt;code_value VARCHAR(255) NOT NULL,&lt;br /&gt;CHECK&lt;br /&gt;(CASE&lt;br /&gt;WHEN code_type = 'DDC'&lt;br /&gt;AND code_value&lt;br /&gt;SIMILAR TO '[0-9][0-9][0-9].[0-9][0-9][0-9]'&lt;br /&gt;THEN 1&lt;br /&gt;WHEN code_type = 'ICD'&lt;br /&gt;AND code_value&lt;br /&gt;SIMILAR TO '[0-9][0-9][0-9].[0-9][0-9][0-9]'&lt;br /&gt;THEN 1&lt;br /&gt;WHEN code_type = 'ISO3166'&lt;br /&gt;AND code_value SIMILAR TO '[A-Z][A-Z]'&lt;br /&gt;THEN 1 ELSE 0 END = 1),&lt;br /&gt;code_description VARCHAR(255) NOT NULL,&lt;br /&gt;PRIMARY KEY (code_value, code_type));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The "SIMILAR TO" predicate is the SQL-92 version of a regular&lt;br /&gt;expression parser based on the POSIX Standards, if you are not&lt;br /&gt;familiar with it. Since the typical application database can have&lt;br /&gt;dozens and dozens of codes in it, just keep extending this pattern for&lt;br /&gt;as long as required. Not very pretty is it? In fact, there is a good&lt;br /&gt;chance that you will exceed the number of WHEN clauses allowed in a&lt;br /&gt;CASE expression. That's why most OTLT programmers don't bother with&lt;br /&gt;it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now let us consider adding new rows to the OTLT.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO OTLT (code_type, code_value, code_description)&lt;br /&gt;VALUES&lt;br /&gt;('ICD', 259.0, 'Inadequate Genitalia after Puberty');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and also&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO OTLT (code_type, code_value, code_description)&lt;br /&gt;VALUES&lt;br /&gt;('DDC', 259.0, 'Christian Pastoral Practices &amp; Religious Orders');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you make an error in the code_type during insert, update or delete,&lt;br /&gt;you have screwed up a totally unrelated value. If you make an error&lt;br /&gt;in the code_type during a query, the results could be interesting.&lt;br /&gt;This can really hard to find when one of the similarly structured&lt;br /&gt;schemes had unused codes in it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The next thing you notice about this table is that the columns are&lt;br /&gt;pretty wide VARCHAR(n), or even worse, that they are NVARCHAR(n) which&lt;br /&gt;can store characters from a strange language. The value of (n) is&lt;br /&gt;most often the largest one allowed in that particular SQL product.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since you have no idea what is going to be shoved into the table,&lt;br /&gt;there is no way to predict and design with a safe, reasonable maximum&lt;br /&gt;size. The size constraint has to be put into the WHEN clause of that&lt;br /&gt;second CHECK() constraint between code_type and code_value. Or you&lt;br /&gt;can live with fixed length codes that are longer or shorter than what&lt;br /&gt;they should be.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;These large sizes tend to invite bad data. You give someone a&lt;br /&gt;VARCHAR(n) column, and you eventually get a string with a lot of white&lt;br /&gt;space and a small odd character sitting at the end of it. You give&lt;br /&gt;someone an NVARCHAR(255) column and eventually it will get a Buddhist&lt;br /&gt;sutra in Chinese Unicode.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now let's consider the problems with actually using the OTLT in a&lt;br /&gt;query. It is always necessary to add the code_type as well as the&lt;br /&gt;value which you are trying to look-up.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT P1.ssn, P1.lastname, .., L1.code_description&lt;br /&gt;FROM OTLT AS L1, Personnel AS P1&lt;br /&gt;WHERE L1.code_type = 'ICD'&lt;br /&gt;AND L1.code_value = P1.disease_code&lt;br /&gt;AND ..;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In this sample query, you need to know the code_type of the Personnel&lt;br /&gt;table disease_code column and of every other encoded column in the&lt;br /&gt;table. If you got a code_type wrong, you can still get a result.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You also need to allow for some overhead for data type conversions.&lt;br /&gt;It might be more natural to use numeric values instead of VARCHAR(n)&lt;br /&gt;for some encodings to ensure a proper sorting order. Padding a string&lt;br /&gt;of digits with leading zeros adds overhead and can be risky if&lt;br /&gt;programmers do not agree on how many zeros to use.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you execute a query, the SQL engine has to pull in the entire&lt;br /&gt;look-up table, even if it only uses a few codes. If one code is at&lt;br /&gt;the start of the physical storage, and another is at the end of&lt;br /&gt;physical storage, I can do a lot of caching and paging. When I update&lt;br /&gt;the OTLT table, I have to lock out everyone until I am finished. It&lt;br /&gt;is like having to carry an encyclopedia set with you when all you&lt;br /&gt;needed was a magazine article.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now consider the overhead with a two-part FOREIGN KEY in a table:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE EmployeeAbsences&lt;br /&gt;(..&lt;br /&gt;code_type CHAR(3) -- min length needed&lt;br /&gt;DEFAULT 'ICD' NOT NULL&lt;br /&gt;CHECK (code_type = 'ICD'),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;code_value CHAR(7) NOT NULL, -- min length needed&lt;br /&gt;FOREIGN KEY (code_type, code_value)&lt;br /&gt;REFERENCES OTLT (code_type, code_value),&lt;br /&gt;..);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now I have to convert the character types for more overhead. Even&lt;br /&gt;worse, ICD has a natural DEFAULT value (000.000 means "undiagnosed"),&lt;br /&gt;while Dewey Decimal does not. Older encoding schemes often used all&lt;br /&gt;9's for "miscellaneous" so they would sort to the end of the reports&lt;br /&gt;in COBOL programs. Just as there is no Magical Universal "id", there&lt;br /&gt;is no Magical Universal DEFAULT value. I just lost one of the most&lt;br /&gt;important features of SQL!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am going to venture a guess that this idea came from OO programmers&lt;br /&gt;who think of it as some kind of polymorphism done in SQL. They say to&lt;br /&gt;themselves that a table is a class, which it isn't, and therefore it&lt;br /&gt;ought to have polymorphic behaviors, which it doesn't.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Maybe there are good reasons for the data modeling principle that a&lt;br /&gt;well-designed table is a set of things of the same kind instead of a&lt;br /&gt;pile of unrelated items.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/881da96ee6c80045/f530775723cb0202#f530775723cb0202"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-8610991687356120475?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/8610991687356120475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=8610991687356120475' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8610991687356120475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8610991687356120475'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/db-table-design-question.html' title='db table design question'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2887348978545688753</id><published>2007-06-04T05:40:00.000-04:00</published><updated>2007-06-04T05:43:50.016-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Range'/><category scheme='http://www.blogger.com/atom/ns#' term='Intersect'/><title type='text'>Find first available block that does not intersect a range</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Given a number of numeric ranges, I need to find the first available row &lt;br /&gt;(range) that can accomodate a requested block of contiguous values. For &lt;br /&gt;example, given the following table definition: &lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[tbl_AllocatedRange]( &lt;br /&gt; [RangeID] [int] IDENTITY(1,1) NOT NULL, &lt;br /&gt; [RangeStart] [bigint] NOT NULL, &lt;br /&gt; [RangeEnd] [bigint] NOT NULL, &lt;br /&gt; CONSTRAINT [PK_tbl_AllocatedRange] PRIMARY KEY CLUSTERED &lt;br /&gt;( &lt;br /&gt; [RangeID] ASC &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And the following DML: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 1, 100, 200 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 2, 500, 650 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 3, 2000, 2200 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 4, 4000, 8000 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 5, 16000, 25000 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 6, 25001, 50000 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO [dbo].[tbl_AllocatedRange] ([RangeID], [RangeStart], [RangeEnd]) &lt;br /&gt; VALUES ( 7, 100000, 200000 ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A request for a block of 10000, should return the row where RangeID=6 &lt;br /&gt;because that is the first available position where I could allocate a &lt;br /&gt;contiguous block of 10000 without intersecting any of the values in the &lt;br /&gt;existing ranges. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Let's add some constraints and reduce those BIGINTs to just INTEGER &lt;br /&gt;unless you really need it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE AllocatedRanges &lt;br /&gt;(range_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; range_start INTEGER NOT NULL &lt;br /&gt; CHECK (range_start &gt;= 0), &lt;br /&gt; range_end INTEGER NOT NULL &lt;br /&gt; CHECK (range_end &gt;= 0), &lt;br /&gt; CHECK (range_start &lt;= range_end)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This will get you all of the candidates, but in RDBMS, there is no &lt;br /&gt;concept of an ordering so talking about the "first avaialble" range &lt;br /&gt;needs more definition. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT range_id, (range_end - range_start)+1 AS range_size, @my_size &lt;br /&gt;AS my_size &lt;br /&gt; FROM AllocatedRanges &lt;br /&gt; WHERE (range_end - range_start)+1 &gt;= @my_size; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We can do it with the lowest range id: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT MIN(range_id) &lt;br /&gt; FROM AllocatedRanges &lt;br /&gt; WHERE (range_end - range_start)+1 &gt;= @my_size; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But the usual requirement is to find the best fit, not the first &lt;br /&gt;one. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT range_id &lt;br /&gt;  FROM AllocatedRanges &lt;br /&gt; WHERE (range_end - range_start)+1 = &lt;br /&gt;    (SELECT MIN((range_end - range_start)+1 - @my_size) &lt;br /&gt;       FROM AllocatedRanges AS A1 &lt;br /&gt;      WHERE ((range_end - range_start)+1 - @my_size) &gt;= 0); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thread/thread/384f1692f50e618/2483231f65d94791#2483231f65d94791"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2887348978545688753?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2887348978545688753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2887348978545688753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2887348978545688753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2887348978545688753'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/find-first-available-block-that-does.html' title='Find first available block that does not intersect a range'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6790842016849592953</id><published>2007-06-04T05:37:00.000-04:00</published><updated>2007-06-04T05:39:17.859-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Refential Integrity'/><title type='text'>mutliple refential integrity</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Suppose I want a column in my table to reference two other columns of &lt;br /&gt;other two tables (of course datatypes are same, and the other two &lt;br /&gt;columns are primary key in their respective relations). How can I &lt;br /&gt;enforce this using SQL? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Suppose I want a column in my table to reference two other columns of other two tables (of course data types are same, and the other two columns are primary key in their respective relations). How can I enforce this using SQL? &lt;&lt;- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Foo &lt;br /&gt;(foo_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; ..); &lt;br /&gt;&lt;br /&gt;CREATE TABLE Bar &lt;br /&gt;(_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; ..); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Foobar &lt;br /&gt;(foo_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Foo(foo_id), &lt;br /&gt; bar_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Bar(bar_id), &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/comp.databases/browse_thread/thread/40fe697649506af1/d8cf547b2aa50d4e#d8cf547b2aa50d4e"&gt;Original Source&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6790842016849592953?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6790842016849592953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6790842016849592953' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6790842016849592953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6790842016849592953'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/06/mutliple-refential-integrity.html' title='mutliple refential integrity'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-5129606182090465403</id><published>2007-05-23T10:57:00.000-04:00</published><updated>2007-05-23T10:58:57.898-04:00</updated><title type='text'>SQL Query Help</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Need to learn SQL queries again (SQL 2005). Need help with the&lt;br /&gt;following situation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have two tables, CUSTOMERS and ORDERS. One each column in these&lt;br /&gt;tables should have identical data (except the name of the column is&lt;br /&gt;different) which is customer's name. Because each order creates an&lt;br /&gt;entry in ORDER table, each customer's name may be appearing more than&lt;br /&gt;once in that table. There could be also instances where a particular&lt;br /&gt;customer might not have placed an order at all and will not have any&lt;br /&gt;entry in the ORDERS table, but do have one entry in CUSTOMERS table&lt;br /&gt;(no duplicates in CUSTOMERS table).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need help with a query which shows a list of customers who have&lt;br /&gt;never placed any orders. This essentially means that they do not have&lt;br /&gt;any entry in the ORDERS table. Here is the Pseudo Code:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select customername from CUSTOMERS table&lt;br /&gt;who are NOT IN&lt;br /&gt;ORDERS table&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Will appreciate any quick thoughts. Thanks in advance!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Need to learn SQL queries again (SQL 2005). &lt;&lt;&gt;&gt; I have two tables, CUSTOMERS and ORDERS. One each column in these tables should have identical data (except the name of the column is different) which is customer's name. &lt;&lt;&gt;&gt; I need help with a query which shows a list of customers who have never placed any orders. &lt;&lt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Wild guess, done without DDL&lt;br /&gt;&lt;br /&gt;SELECT C.customer_name&lt;br /&gt;FROM Customers AS C&lt;br /&gt;WHERE NOT EXISTS&lt;br /&gt;(SELECT *&lt;br /&gt;FROM Orders AS O&lt;br /&gt;WHERE O.customer_name = C.customer_name);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-5129606182090465403?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/5129606182090465403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=5129606182090465403' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5129606182090465403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/5129606182090465403'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/sql-query-help.html' title='SQL Query Help'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-1005371390086921278</id><published>2007-05-23T10:55:00.000-04:00</published><updated>2007-05-23T10:57:17.847-04:00</updated><title type='text'>Totals</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a table that is populated everyday with daily totals, I'm &lt;br /&gt;trying to teach myself SQL using this table. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Someone kindly gave me a query that gave the weekly totals based on &lt;br /&gt;the table: &lt;br /&gt;SELECT     week_start, week_start + 6 AS week_end, SUM(Total3) AS &lt;br /&gt;production &lt;br /&gt;FROM         (SELECT     Date - DATEPART(weekday, Date + @@DATEFIRST - &lt;br /&gt;1) + 1 AS week_start, Total3 &lt;br /&gt;                       FROM          dbo.A_Totals)  AS d &lt;br /&gt;GROUP BY week_start &lt;br /&gt;ORDER BY week_start &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How can I adapt this to divide the weekly totals into years so I'd &lt;br /&gt;have: week number, year, year-1,year-2 etc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks in advance &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  I have a table that is populated everyday with daily totals, I'm trying to teach myself SQL using this table. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bad idea; get a good book and a tutorial, then work on a problem. &lt;br /&gt;&lt;br /&gt;Your approach to SQL is typical of someone coming in via procedural &lt;br /&gt;code and looking for functions to solve it.  SQL is a data retrieval &lt;br /&gt;language that likes to use sets (tables).  This is a WHOLE DIFFERENT &lt;br /&gt;PROGRAMMING PARADIGM. After you have a few basics, then look up the &lt;br /&gt;use of calendars -- temporal stuff is one of the hardest parts of &lt;br /&gt;RDBMS, so it is a horrible starting point for a self-education.  Try &lt;br /&gt;something like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE ReportPeriods &lt;br /&gt;(period_name VARCHAR(20) NOT NULL PRIMARY KEY, &lt;br /&gt; start_date DATETIME NOT NULL, &lt;br /&gt; end_date DATETIME NOT NULL, &lt;br /&gt; CHECK (start_date &lt; end_date)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create and load a table of reporting periods of whatever range you &lt;br /&gt;want.  They can overlap, have gaps, etc. They can be crazy, one shot &lt;br /&gt;things, etc.  If you are a Don Martin fan: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO ReportPeriods &lt;br /&gt;VALUES ('National Gorilla Suit Week', 2007-05-21', 2007-05-27'); &lt;br /&gt;etc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You also have to learn to design data which should take about a year, &lt;br /&gt;if you really work at it.  So if your weeks are encoding the ISO-8601 &lt;br /&gt;year-week number format, then you can simply write: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT period_name, SUM(some_col) AS week_total &lt;br /&gt;   FROM DailyReports AS D, ReportPeriods AS R &lt;br /&gt;  WHERE D.report_date BETWEEN start_date AND end_date &lt;br /&gt;    AND period_name LIKE 'WEEK-2007__; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Change the wild cards as needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-1005371390086921278?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/1005371390086921278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=1005371390086921278' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1005371390086921278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1005371390086921278'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/totals.html' title='Totals'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-1920952243440442953</id><published>2007-05-11T08:54:00.000-04:00</published><updated>2007-05-11T08:55:35.668-04:00</updated><title type='text'>Correct Way to Insert into Multiple Tables</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am just wondering if what I am doing would be considered the correct &lt;br /&gt;way to insert data into multiple tables when a forigen key is in place &lt;br /&gt;between the tables primary keys. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is a simple DB structure &lt;br /&gt;Table 1 &lt;br /&gt;ID int (auto incriment) Primary Key &lt;br /&gt;FirstName varchar(100) &lt;br /&gt;LastName varchar(200) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Table 2 &lt;br /&gt;ID (Primary Key) &lt;br /&gt;Age int &lt;br /&gt;BirthPlace varchar(100) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have created the following sotred proceedure, it works from the test I &lt;br /&gt;have done, but I am wondering if it is the *correct* way to do it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PROCEDURE [dbo].[InsertPerson] &lt;br /&gt;        @ID int output, &lt;br /&gt;        @FirstName varchar(100), &lt;br /&gt;        @LastName varchar(200), &lt;br /&gt;        @Age int, &lt;br /&gt;        @BirthPlace varchar(100) &lt;br /&gt;AS &lt;br /&gt;Insert into dbo.UserInfo(FirstName, LastName) &lt;br /&gt;Values(@FirstName, @LastName) &lt;br /&gt;SET @ID = SCOPE_IDENTITY() &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Insert into dbo.UserDetails(ID, Age, BirthPlace) &lt;br /&gt;Values (@ID, @Age, @BirthPlace) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I am just wondering if what I am doing would be considered the correct  way to insert data into multiple tables when a forigen key is in place  between the tables primary keys. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;And what you have done is wrong on several points. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) an auto-increment cannot ever be used as a key in an RDBMS.   A key &lt;br /&gt;is a subset of attributes in the data model.  An auto-increment is &lt;br /&gt;inside the hardware and has nothing to do with the data model, &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) Do you really have names that long?  Well, you will if you allow &lt;br /&gt;it, &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Why did you split information of what-ever-the-heck you are &lt;br /&gt;modeling across two tables? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4) "age" of what?  Ands we never store age; we store a birthdate so we &lt;br /&gt;can always correctly compute the age.  Is this what you wanted? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Customers &lt;br /&gt;(cust_id CHAR(9) NOT NULL PRIMARY KEY &lt;br /&gt;   CHECK (&lt;&lt; validation constraint&gt;&gt;), &lt;br /&gt; last_name VARCHAR(20) NOT NULL, &lt;br /&gt; first_name VARCHAR(20) NOT NULL, &lt;br /&gt; birth_date DATETIME NOT NULL, &lt;br /&gt; birth_location  VARCHAR(20) NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The problem goes away with a valid design.  I think what you might &lt;br /&gt;have wanted to know is that INSERT INTO statements work on one and &lt;br /&gt;only one base table.  Put both inserts into a single transaction and &lt;br /&gt;add a PRIMARY KEY and FOREIGN KEY constraints.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-1920952243440442953?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/1920952243440442953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=1920952243440442953' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1920952243440442953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1920952243440442953'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/correct-way-to-insert-into-multiple.html' title='Correct Way to Insert into Multiple Tables'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6246185618184831736</id><published>2007-05-11T08:53:00.000-04:00</published><updated>2007-05-11T08:54:13.602-04:00</updated><title type='text'>Last Day Of Previous Month...with a twist</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a requirement to design a query that identifies items sold &lt;br /&gt;between two dates. There is a 'SoldDate' datetime field used to &lt;br /&gt;register what date the item was sold. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The query needs to identify all sales between the last day of the &lt;br /&gt;previous month and going back one year. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What I would like to do is to design a query / stored procedure that &lt;br /&gt;will dynamically create the criteria to allow the client to simply run &lt;br /&gt;the query or stored proc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; I know how to establish the last day of the previous month part, I'm &lt;br /&gt;just not sure of how best to design the remainder of the query. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I know how to establish the last day of the previous month part, I'm  just not sure of how best to design the remainder of the query. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Instead of using procedural coding, why not use a table of the &lt;br /&gt;reporting periods for a decade or two?  A simple BETWEEN predicate &lt;br /&gt;will classify each sale quickly and give you extra control over non- &lt;br /&gt;operating days, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6246185618184831736?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6246185618184831736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6246185618184831736' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6246185618184831736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6246185618184831736'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/last-day-of-previous-monthwith-twist.html' title='Last Day Of Previous Month...with a twist'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2049323241464074672</id><published>2007-05-11T08:51:00.000-04:00</published><updated>2007-05-11T08:53:00.838-04:00</updated><title type='text'>difficulty with SQL to get view</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; am having difficulty in designing my SQL. :( &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In this setup, an Invoice can have multiple Bills (installment &lt;br /&gt;payments). I would like a query that returns invoices with overdue &lt;br /&gt;bills &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a bill is overdue if :: NOT B_Paid and Now() &gt; B_DueDate    --- how to &lt;br /&gt;put this in the following '???' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT B_Invoice, ??? As Overdue &lt;br /&gt;FROM T_Bill &lt;br /&gt;GROUP BY B_Invoice &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE T_Bill ( &lt;br /&gt;    RefNo                       INTEGER         IDENTITY PRIMARY KEY, &lt;br /&gt;    B_Invoice                   INTEGER         NOT NULL REFERENCES &lt;br /&gt;T_Invoice, &lt;br /&gt;    B_BillDate                  SMALLDATETIME   DEFAULT CURRENT_TIMESTAMP &lt;br /&gt;NOT NULL, &lt;br /&gt;    B_DueDate                   SMALLDATETIME   DEFAULT (CURRENT_TIMESTAMP &lt;br /&gt;+14) NOT NULL, &lt;br /&gt;    B_Paid                      BIT             DEFAULT 0 NOT NULL, &lt;br /&gt;    B_PaidDate                  SMALLDATETIME   DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt;    B_PaymentInfo               VARCHAR(24)     DEFAULT '???' NOT NULL &lt;br /&gt;); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Your table is not designed properly.  Your assembly-style bit flag is &lt;br /&gt;redundant when you have a payment date.  IDENTITY cannot be a &lt;br /&gt;relational key by definition and it is redundant given the invoice &lt;br /&gt;number.  You never put the table as a prefix on a data element names &lt;br /&gt;because that would change the names from table to table.  If the due &lt;br /&gt;date is always 14 days after the billing date, then put compute it in &lt;br /&gt;a VIEW or a query instead of wasting space.  This also gives you more &lt;br /&gt;control without having to alter the tables. &lt;br /&gt;&lt;br /&gt;CREATE TABLE Billings &lt;br /&gt;(invoice_nbr INTEGER NOT NULL &lt;br /&gt;   REFERENCES Invoices (invoice_nbr), &lt;br /&gt; billing_date DATETIME NOT NULL, &lt;br /&gt; PRIMARY KEY (invoice_nbr, billing_date), &lt;br /&gt; paid_date DATETIME, -- null is unpaid &lt;br /&gt; payment_note VARCHAR(24) DEFAULT '???' NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I would like a query that returns invoices with overdue bills  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT invoice_nbr, CURRENT_TIMESTAMP &lt;br /&gt;  FROM Billings &lt;br /&gt;WHERE paid_date IS NULL &lt;br /&gt;  AND DATEADD (D, billing_date, 14) &gt;= CURRENT_TIMESTAMP; &lt;br /&gt;&lt;br /&gt;You need to get a book on basic data modeling.  And one on RDBMS. &lt;br /&gt;What you have is a badly designed punch card file system, with flag, &lt;br /&gt;sequential numbering, etc. .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2049323241464074672?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2049323241464074672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2049323241464074672' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2049323241464074672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2049323241464074672'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/difficulty-with-sql-to-get-view.html' title='difficulty with SQL to get view'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-8382388418801850587</id><published>2007-05-08T12:54:00.000-04:00</published><updated>2007-05-08T13:00:15.048-04:00</updated><title type='text'>Simple update question</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Greetings, &lt;br /&gt;     I have a simple update query in Sql 2k and want to update only &lt;br /&gt;one field instead of all 3 fields. &lt;br /&gt;&lt;br /&gt;Update customer set &lt;br /&gt;           Name = @inName, &lt;br /&gt;           City   = @inCity &lt;br /&gt;           State = Case when @instate is not null then @instate else &lt;br /&gt;State end &lt;br /&gt;  Where Customer = @inCust &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I would like to know what's the best way to prevent not to update all &lt;br /&gt;3 field when updating only one. If I use the case statement then check &lt;br /&gt;for @instate if not null then itself - would this prevent &lt;br /&gt;from updating the third field.  Is there a better way to do this &lt;br /&gt;update.  Thanks in advance. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; The question is by updating all fields [sic] isn't too much overhead for SQL Server 2k to deal with?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You missed one of the major points of SQL.  The unit of work is the &lt;br /&gt;entire row and not the columns within a row.  This is one of the many, &lt;br /&gt;many ways that newbies confuse rows and records, fields and columns. &lt;br /&gt;This is why we have OLD and NEW (called INSERTED and DELETED in local &lt;br /&gt;dialect) in the SQL update model.  Records are updated a field at a &lt;br /&gt;time in file systems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-8382388418801850587?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/8382388418801850587/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=8382388418801850587' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8382388418801850587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/8382388418801850587'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/simple-update-question.html' title='Simple update question'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-9131774311509967400</id><published>2007-05-04T13:31:00.000-04:00</published><updated>2007-05-04T13:32:39.406-04:00</updated><title type='text'>Stored Procedures---Stacking IFs</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;What is the proper syntax for stacking these IFs in a Stored Procedure??? &lt;br /&gt;&lt;br /&gt;Thanks in advance... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        IF @Loan_Nbr IS NOT NULL &lt;br /&gt;        IF @MTM_Losses_Accrued IS NOT NULL &lt;br /&gt;        IF EXISTS ( SELECT 1 FROM [DMD_Data]..[UDF_WARRANTY]            WARRANTY &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; What is the proper syntax for stacking these IFs in a Stored Procedure &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What the hell are you talking about?? IF-THEN-ELSE-ENDIF constructs in &lt;br /&gt;any procedural programming language are nested or sequential.  This &lt;br /&gt;has nothing to why SQL.  Don't you know how to program in ANY &lt;br /&gt;language??!! &lt;br /&gt;&lt;br /&gt;Please something that makes sense when you are sober&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-9131774311509967400?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/9131774311509967400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=9131774311509967400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/9131774311509967400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/9131774311509967400'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/stored-procedures-stacking-ifs.html' title='Stored Procedures---Stacking IFs'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4382644185554773626</id><published>2007-05-04T13:27:00.000-04:00</published><updated>2007-05-04T13:30:14.197-04:00</updated><title type='text'>Naming Conventions</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm coming from a MS Access background and so I'm very used to and &lt;br /&gt;comfortable with the hungarian (Leszynski et al) naming conventions. &lt;br /&gt;However, I'm getting started into my first SQL Server Database and &lt;br /&gt;really want to use the appropriate up to date standard naming &lt;br /&gt;convention (ISO compliant). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I think I have the general idea from raking though countless &lt;br /&gt;conflicting sites and posts, but I'm a bit stuck on what to do &lt;br /&gt;regarding pk / fk naming &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For example, in my MS Access world I would have two tables: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblOrders &lt;br /&gt;======= &lt;br /&gt;strOrderID &lt;br /&gt;intCustomerID &lt;br /&gt;dtOrderDate &lt;br /&gt;... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblCustomers &lt;br /&gt;========== &lt;br /&gt;intCustomerID &lt;br /&gt;strCustomerName &lt;br /&gt;... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So what would the appropriate and most up-to-date and standard naming &lt;br /&gt;be for SQL Server? My Guess: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Orders &lt;br /&gt;===== &lt;br /&gt;Ord_Order_ID_Pk &lt;br /&gt;Ord_Customer_ID_Fk &lt;br /&gt;Ord_Order_Date &lt;br /&gt;... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Customers &lt;br /&gt;======== &lt;br /&gt;Cus_Customer_ID_Pk &lt;br /&gt;Cus_Customer_Name &lt;br /&gt;... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How close (or far) am I from "Celko Proof" naming here? &lt;br /&gt;All help gratefully accepted! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I'm getting started into my first SQL Server Database and really want to use the appropriate up to date standard naming convention (ISO compliant). &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Get a copy of SQL PROGRAMMING STYLE.  Back in the early 1980's I &lt;br /&gt;worked for &lt;br /&gt;AIRMICS (Army Institute for Research in Management Information &amp; &lt;br /&gt;Computer Sciences) and researched code formatting.  I based the book &lt;br /&gt;on the ISO-11179 rules and a set of postfixes from Teradata, the other &lt;br /&gt;data warehouse vendor and other meta data projects. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I think I have the general idea from raking though countless conflicting sites and posts, &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Get the book -- I give the DoD, ISO, etc. Standards. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; .. but I'm a bit stuck on what to do regarding pk / fk naming &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Same as any other data element; the principle to name it for what it &lt;br /&gt;is.  Not for how is implemented.  Not for how it is used in one place. &lt;br /&gt;&lt;br /&gt; &gt;&gt; For example, in my MS Access world I would have two tables: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; tblOrders &lt;br /&gt; ======= &lt;br /&gt; strOrderID &lt;br /&gt; intCustomerID &lt;br /&gt; dtOrderDate &lt;br /&gt; ... &lt;br /&gt;&lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In a valid data model this would be: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Orders -- "tbl-" is silly and redundant &lt;br /&gt;(order_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; customer_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Customers (customer_id), &lt;br /&gt; order_date DATE DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt;  ..); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your prefixes deal with data types (implementations) and not the &lt;br /&gt;nature of the data element.  They are also redundant in many cases: &lt;br /&gt;SQL has only one data structure, the Table (derived, CTE, virtual, &lt;br /&gt;base, but still a table) and an order_date does not need a prefix to &lt;br /&gt;repeat the postfix.  All those prefixes have done is screw the hell &lt;br /&gt;out of your data dictionary. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Customers &lt;br /&gt;( customer_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; customer_name VARCHAR(35) NOT NULL, &lt;br /&gt; ..); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Ord_Order_ID_Pk &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     Ord_Customer_ID_Fk &lt;br /&gt;     Ord_Order_Date  &lt;&lt; &lt;br /&gt;&lt;br /&gt;NO! NO! NO!   The " Ord_Customer_ID_Fk" is the same data element as &lt;br /&gt;the "Cus_Customer_ID_Pk" and should have the same data element name in &lt;br /&gt;the entire schema.  Do you change your fingerprints when you walk from &lt;br /&gt;room to room in your house?  Same thing here.  Different names would &lt;br /&gt;mean they are logically different data elements and they are not.  The &lt;br /&gt;PK- FK- crap is how they are used locally and not what they are by &lt;br /&gt;their nature.  You qualify the location with "&amp;lt;table name&amp;gt;.&amp;lt;attribute &lt;br /&gt;name&amp;gt;" when it is not clear. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; How close (or far) am I from "Celko Proof" naming here? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You did get the idea that a table is a collective or plural noun &lt;br /&gt;because it is a set of more than one entity (exception -- if it really &lt;br /&gt;is just one entity, use a singular name, but you do not see many of &lt;br /&gt;those). &lt;br /&gt;&lt;br /&gt;And you did not do something really stupid like have a "type_id" &lt;br /&gt;affix.  How can an attribute be both an identifier and a type at the &lt;br /&gt;same time?  Hey, lets go all out for a "type_id_value_name" postfix!! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And you did not have a magical universal "id" on every table to mimic &lt;br /&gt;a sequential file record number for a physical locater.  Such people &lt;br /&gt;are called "ID-iots" in my book :) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'd give you a solid C+ , but not a C++ :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4382644185554773626?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4382644185554773626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4382644185554773626' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4382644185554773626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4382644185554773626'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/naming-conventions.html' title='Naming Conventions'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3842475390646815050</id><published>2007-05-04T13:25:00.000-04:00</published><updated>2007-05-04T13:26:49.586-04:00</updated><title type='text'>Proper Case</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a ProperCase function that works well.  However, I'm constantly &lt;br /&gt;adding "exceptions" into the funciton.  For example, I want IPA uppercase, &lt;br /&gt;but not when it's in constIPAtion.  This got me to thinking that it might be &lt;br /&gt;easier to add all my cases into a table, rather than constantly editing my &lt;br /&gt;function.  But it's not working quite the way I'd expect it to.  So rather &lt;br /&gt;than reinvent the wheel, I thought I'd come here and see if anyone has taken &lt;br /&gt;a table approach to ProperCase.  If so, can you please share how you did &lt;br /&gt;this? &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; So rather than reinvent the wheel, I thought I'd come here and see if anyone has taken  a table approach to ProperCase. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Get a copy of SQL PROGRAMMING STYLE for more than you probably want to &lt;br /&gt;know..  Formatting code was one of the big issues of the day when I &lt;br /&gt;was a researcher at AIRMICS (Army Institute for Research in Management &lt;br /&gt;Information &amp; Computer Sciences) in the early 1980's.  A summary is: &lt;br /&gt;&lt;br /&gt;1) For people who read languages in a Latin alphabet, the eye tends to &lt;br /&gt;jump to the uppercase letters -- they start sentences and proper &lt;br /&gt;nouns, so they mark "special things" in the language.  This is one &lt;br /&gt;reason even MS dropped "camelCase" -- it jerks the eye around, &lt;br /&gt;mentally and physically. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) Uppercase words are read as Boumas (single units recognized by &lt;br /&gt;shape).  That is why the keywords in a program should be uppercase; &lt;br /&gt;you wan to read them as a structure in which user words are held &lt;br /&gt;(compilers will not let you misspell them, unlike written English &lt;br /&gt;where all uppercase is horrible) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) lowercase letters are actually read (as opposed to eating them as a &lt;br /&gt;shape) and misspelling can be quickly seen.  Newspapers and books knew &lt;br /&gt;this centuries ago.  That is why you use them for column names, &lt;br /&gt;variables and so forth.  But Capitalize (or ProperCase) schema &lt;br /&gt;objects, like table and view names because they are proper nouns. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The underscore is much better than either camelCase or ProperCase. &lt;br /&gt;The eye can see the two parts of the the ISO-11179 names easily and &lt;br /&gt;read the postfix to learn the nature of the attribute without being &lt;br /&gt;jerked to the uppercase letters. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;These tested rules are much easier to implement in a language with &lt;br /&gt;string functions than using a big look-up table in SQL. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Good naming conventions and formatting can reduce maintenance time by &lt;br /&gt;8-12% and since that is where the real cost is, it is worth the &lt;br /&gt;effort.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3842475390646815050?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3842475390646815050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3842475390646815050' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3842475390646815050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3842475390646815050'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/05/proper-case.html' title='Proper Case'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2434040178484044444</id><published>2007-04-27T20:53:00.000-04:00</published><updated>2007-04-27T20:56:02.268-04:00</updated><title type='text'>joining on same table multiple times on different values</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Having perfomance problems with this query (returning to many rows and &lt;br /&gt;takening to long), related I think &lt;br /&gt;to joining on the DomainDetail table 3 times. &lt;br /&gt;Is there a better way to do this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT SO.SystemOrderID AS Order_ID, &lt;br /&gt; SO.SystemOrderTypeID AS Order_TypeID, &lt;br /&gt; SO.OrderStatusID AS Order_StatusID, &lt;br /&gt; SO.CreateDate AS Order_CreateDate,&lt;br /&gt;DD.[Name] AS Detail_Status &lt;br /&gt;        DD1.Name AS Detail_Type &lt;br /&gt; DD2.Name AS Order_Status &lt;br /&gt; FROM MyDatabase3.dbo..SystemOrder SO &lt;br /&gt;     INNER JOIN MyDatabase2.dbo..SystemOrderDetail SOD &lt;br /&gt;          ON SOD.SystemOrderID = SO.SystemOrderID &lt;br /&gt;  INNER JOIN MyDatabase1.dbo.DomainDetail DD &lt;br /&gt;  ON SOD.DetailStatusID = DD.DomainValue &lt;br /&gt; INNER JOIN  MyDatabase1.dbo.DomainDetail DD1 &lt;br /&gt;  ON SOD.DetailTypeID = DD1.DomainValue &lt;br /&gt; INNER JOIN MyDatabase1.dbo.DomainDetail DD2 &lt;br /&gt;  ON SO.OrderStatusID = DD2.DomainValue &lt;br /&gt;WHERE SO.CreateDate &gt; dateadd(month,-13,getdate())AND &lt;br /&gt; SOD.CreateDate &gt; dateadd(month,-13,getdate())AND &lt;br /&gt; DD.DomainID IN(125,126,127) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;I first re-wrote your query to bring the names closer to ISO-11179, &lt;br /&gt;remove the display headers in the SELECT list and get rid of redundant &lt;br /&gt;predicates like "SOD.system_order_id = SO.system_order_id" (that &lt;br /&gt;happens a lot with the infixed syntax ). Untested I got this. &lt;br /&gt;&lt;br /&gt;SELECT SO.system_order_id, SO.system_order_type, &lt;br /&gt;       SO.order_status, SO.create_date, &lt;br /&gt;       DD.name AS detail_status &lt;br /&gt;       DD1.name AS detail_type &lt;br /&gt;       DD2.name AS order_status &lt;br /&gt; FROM Mydatabase3.DBO..System_Order AS SO, &lt;br /&gt;      Mydatabase2.DBO..System_Orderdetail AS SOD, &lt;br /&gt;      Mydatabase1.DBO.Domaindetail AS DD, &lt;br /&gt;      Mydatabase1.DBO.Domaindetail AS DD1, &lt;br /&gt;      Mydatabase1.DBO.Domaindetail AS DD2 &lt;br /&gt;WHERE SOD.detail_status = DD.domain_value &lt;br /&gt;  AND SOD.detail_type = DD1.domain_value &lt;br /&gt;  AND SO.order_status = DD2.domain_value &lt;br /&gt;  AND SOD.system_order_id = SO.system_order_id &lt;br /&gt;  AND SO.create_date &gt; DATEADD(MONTH, -13, CURRENT_TIMESTAMP) &lt;br /&gt;  AND SOD.create_date &gt; DATEADD(MONTH, -13, CURRENT_TIMESTAMP) &lt;br /&gt;  AND DD.domain_id IN (125, 126, 127); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What you posted scares me.  First of all, there is no such thing as a &lt;br /&gt;"type_id" in a valid data model-- an attribute can be an identifier or &lt;br /&gt;a type, but NEVER both at once. Ditto for "status_id" data element. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is your order information spread across three databases (mydatabase3, &lt;br /&gt;mydatabase2, mydatabase1)?  That just does not work; a data model &lt;br /&gt;needs to be in one place.  I am still trying to make sense of the &lt;br /&gt;"system-" prefix -- what is a "System_orders" entity and why is it &lt;br /&gt;logically different from a plain "Orders" table? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There is a magical column with the uselessly vague name "name" that is &lt;br /&gt;equivalent to "detail_status", "detail_type" and "order_status".  But &lt;br /&gt;a type and a status are very different kinds of attributes, just as &lt;br /&gt;orders and details are very different kinds of entities.  Ditto for &lt;br /&gt;the equally magical "domain_value" data element.  We need to know &lt;br /&gt;"name of WHAT!?" to make sense of this. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am going to make a guess that this schema: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) Mixes data and metadata.  The choice of names implies this strongly &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) Has non-scalar columns.  We know that already from your magical &lt;br /&gt;changing columns.  Do you find the meaning of the magical domain_value &lt;br /&gt;from the domain_id? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Has split entities across tables, which is probably why you have &lt;br /&gt;multiple databases. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are.  Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2434040178484044444?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2434040178484044444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2434040178484044444' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2434040178484044444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2434040178484044444'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/joining-on-same-table-multiple-times-on.html' title='joining on same table multiple times on different values'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-2079943166353579842</id><published>2007-04-22T12:48:00.000-04:00</published><updated>2007-04-22T12:50:02.696-04:00</updated><title type='text'>dynamically change column name when displaying</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a table, after i query the table for displaying, several column names &lt;br /&gt;will be changed based on the condition, but I don't want change the acutal &lt;br /&gt;table column names, it will only be changed when displaying. &lt;br /&gt;I tried CTE and virtual table with column aliases, but they doesn't work, &lt;br /&gt;they require you know the column name first, i CANNOT pass @columnName to &lt;br /&gt;them. &lt;br /&gt;&lt;br /&gt;I can certainly create a temp table and copy all the data from the orginal &lt;br /&gt;table, and then based on the condition to rename the column name of the temp &lt;br /&gt;table, then display it, but that is not efficient. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;You have missed the ENTIRE CONCEPT OF A TIERED ARCHITECTURE!! &lt;br /&gt;&lt;br /&gt;You NEVER query a table for display; you query a table for **data** &lt;br /&gt;and the front end does their display.  You are writing 1950's file &lt;br /&gt;systems in SQL!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-2079943166353579842?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/2079943166353579842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=2079943166353579842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2079943166353579842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/2079943166353579842'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/dynamically-change-column-name-when.html' title='dynamically change column name when displaying'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6163573706598427163</id><published>2007-04-22T12:41:00.000-04:00</published><updated>2007-04-22T12:46:20.311-04:00</updated><title type='text'>Outline number sorting</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Is there a way to in SQL to sort outline numbers to retain the &lt;br /&gt;"natural order" state? &lt;br /&gt;&lt;br /&gt;E.g.: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.1 &lt;br /&gt;1.2 &lt;br /&gt;1.3 &lt;br /&gt;1.10 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Shows up now as: &lt;br /&gt;1.1 &lt;br /&gt;1.10 &lt;br /&gt;1.2 &lt;br /&gt;1.3 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there any way to use recursive functionality to check for longer &lt;br /&gt;outline numbers (i.e., like 1.1.1.1.1)? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Is there a way to in SQL to sort outline numbers to retain the "natural order" state? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I use this system in my books and other things a lot.  My solution is &lt;br /&gt;to pad each section with leading zeros and hope I never have more than &lt;br /&gt;99 headings. &lt;br /&gt;&lt;br /&gt;00.00. &lt;br /&gt;01.00. &lt;br /&gt;01.01 &lt;br /&gt;01.01.02. &lt;br /&gt;etc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You enforce this with LIKE predicates and ORs in the DDL rather than &lt;br /&gt;trying to do it in the DML.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6163573706598427163?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6163573706598427163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6163573706598427163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6163573706598427163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6163573706598427163'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/outline-number-sorting.html' title='Outline number sorting'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4897320867948790986</id><published>2007-04-22T12:39:00.000-04:00</published><updated>2007-04-22T12:41:47.818-04:00</updated><title type='text'>Stored procedure returns duplicates</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am trying to create a report in Crystal Reports (v 8.5). I have a&lt;br /&gt;stored procedure to pull data from two databases and parameters.&lt;br /&gt;There are multiple one-to-many relationships and the stored procedure&lt;br /&gt;returns duplicates; e.g., one schedule may have multiple resources,&lt;br /&gt;supplies, and/or orders (and one order may have multiple foods). Is&lt;br /&gt;there a way to stop the duplication?&lt;br /&gt;&lt;br /&gt;The stored procedure looks like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;***************************************************************************&amp;shy;*********&lt;br /&gt;SET QUOTED_IDENTIFIER OFF&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET ANSI_NULLS OFF&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE usp_rpt1 (&lt;br /&gt;@start_date smalldatetime,&lt;br /&gt;@end_date smalldatetime,&lt;br /&gt;@rpt_type varchar(3),&lt;br /&gt;@rpt_id int&lt;br /&gt;)&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;set nocount on&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--Set up some string variables to build the selection query for the&lt;br /&gt;parameters supplied&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;declare @fields varchar(255)&lt;br /&gt;declare @tables varchar(255)&lt;br /&gt;declare @where varchar(2000)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE #tmp_sched(sched_id int, rpt_type_desc varchar(100),&lt;br /&gt;rpt_id int)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;set end_date = midnight of next day&lt;br /&gt;SELECT @end_date = DATEADD(day,1,@end_date)&lt;br /&gt;SELECT @end_date = CONVERT(smalldatetime,&lt;br /&gt;CONVERT(varchar(4),YEAR(@end_date)) + '-'&lt;br /&gt;+&lt;br /&gt;CONVERT(varchar(2),MONTH(@end_date)) + '-'&lt;br /&gt;+&lt;br /&gt;CONVERT(varchar(2),DAY(@end_date))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;IF @rpt_type = 'LOC'&lt;br /&gt;INSERT INTO #tmp_sched&lt;br /&gt;SELECT DISTINCT s.sched_id, l.loc_desc, l.loc_id&lt;br /&gt;FROM tbl_sched s&lt;br /&gt;LEFT JOIN tbl_sched_res_date srd ON s.sched_id = srd.sched_id&lt;br /&gt;LEFT JOIN tbl_res r ON srd.res_id = r.res_id&lt;br /&gt;LEFT JOIN tbl_grp g ON r.grp_id = g.grp_id&lt;br /&gt;LEFT JOIN tbl_loc l ON g.loc_id = l.loc_id&lt;br /&gt;WHERE l.loc_id = CONVERT(varchar(12),@rpt_id)&lt;br /&gt;AND g.obsolete_flag = 0&lt;br /&gt;AND r.obsolete_flag = 0&lt;br /&gt;ANd l.obsolete_flag = 0&lt;br /&gt;AND s.deleted_flag = 0&lt;br /&gt;AND srd.mtg_start_date_local &gt;=&lt;br /&gt;CONVERT(varchar(20), @start_date, 1)&lt;br /&gt;AND srd.mtg_start_date_local &lt; rpt_type =" 'GRP'" sched_id =" srd.sched_id" res_id =" r.res_id" grp_id =" g.grp_id" grp_id =" CONVERT(varchar(12),@rpt_id)" parent_grp_id =" CONVERT(varchar(12),@rpt_id))" obsolete_flag =" 0" obsolete_flag =" 0" deleted_flag =" 0"&gt;=&lt;br /&gt;CONVERT(varchar(20), @start_date, 1)&lt;br /&gt;AND srd.mtg_start_date_local &lt; rpt_type =" 'RES'" sched_id =" srd.sched_id" res_id =" r.res_id" res_id =" CONVERT(varchar(12),@rpt_id)" obsolete_flag =" 0" deleted_flag =" 0"&gt;=&lt;br /&gt;CONVERT(varchar(20), @start_date, 1)&lt;br /&gt;AND srd.mtg_start_date_local &lt; rpt_type =" 'REG'" sched_id =" srd.sched_id" res_id =" r.res_id" grp_id =" g.grp_id" loc_id =" l.loc_id" loc_id =" reg.region_id" region_id =" CONVERT(varchar(12),@rpt_id)" obsolete_flag =" 0" obsolete_flag =" 0" obsolete_flag =" 0" obsolete_flag =" 0" deleted_flag =" 0"&gt;=&lt;br /&gt;CONVERT(varchar(20), @start_date, 1)&lt;br /&gt;AND srd.mtg_start_date_local &lt; sched_id =" srd.sched_id" res_id =" r.res_id" grp_id =" g.grp_id" grp_id =" 0" parent_grp_id =" 0)" obsolete_flag =" 0" obsolete_flag =" 0" deleted_flag =" 0"&gt;=&lt;br /&gt;CONVERT(varchar(20), @start_date, 1)&lt;br /&gt;AND srd.mtg_start_date_local &lt; description =" ts.rpt_type_desc," date =" CONVERT(varchar(12),srd.mtg_start_date_local,101)," starttime =" srd.mtg_start_date_local," endtime =" srd.mtg_end_date_local," schedid =" s.sched_id," meetingtitle =" s.sched_desc," resourceused =" r.res_desc," resourcesetup =" su.setup_desc" numberofattendees =" Attendees.string_value," orderid =" ord.order_id," foodqty =" CONVERT" fooddesc =" i.item_name," side =" sidei.item_name," meetingdesc =" ord.order_desc," supplies =" suppliesudf.udf_desc," suppliesval =" supplies.value," accountcode =" ord.order_user_acct_code," cateringnotes =" ord.order_notes," foodnotes =" oi.order_notes" sched_id =" s.sched_id" sched_id =" srd.sched_id" res_id =" r.res_id" sched_id =" srs.sched_id" res_id =" srs.res_id" setup_id =" rs.setup_id" res_id =" rs.res_id" setup_id =" su.setup_id" sched_id =" supplies.sched_id" request_tab_id =" (SELECT" request_tab_hdr =" 'A)" request_tab_id =" (SELECT" request_tab_hdr =" 'Mtg" udf_id =" suppliesudf.udf_id" sched_id =" s.sched_id" udf_id =" (SELECT" udf_desc =" 'Number" sched_id =" s.sched_id" udf_id =" (SELECT" udf_desc =" 'Meeting" order_sched_id =" s.sched_id" order_id =" oi.order_id" menu_item_id =" mi.menu_item_id" item_id =" i.item_id" order_item_id =" side.order_item_id" item_id =" sidei.item_id" deleted_flag =" 0" deleted_flag =" 0"&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Any suggestion is greatly appreciated. &lt;&lt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;EVERYTHING you are doing is TOTALLY wrong. You have just been cussed&lt;br /&gt;out by one of the people who wrote this language. If you have brain&lt;br /&gt;instead of an ego, you might want to listen.&lt;br /&gt;&lt;br /&gt;This is a (bad) COBOL program written in SQL! There is so much&lt;br /&gt;formatting done in SQL code! The bad news -- for me-- is that this&lt;br /&gt;code is so awful I cannot use it in my next book as a bad example&lt;br /&gt;because it is too proprietary! You could be famous!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your code is so awful, you even use the "tbl-" prefixes to tell us you&lt;br /&gt;have no idea about RDBMS! You keep converting dates to strings because&lt;br /&gt;you are writing COBOL in SQL and want strings!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why do your have "CREATE TABLE #tmp_sched" when view would work?&lt;br /&gt;Answer: because magnetic tape files have to be materialized&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why do you spit on ISO-11179 rules and use a "tbl-" prefix? Because&lt;br /&gt;you know only BASIC programming, which needs the prefixes for the one&lt;br /&gt;pass compiler.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You write SQL with flags like it was 1950's Assembly language! Flags&lt;br /&gt;in SQL!! Ghod Damn!! Varying length identifiers!? And I loved the way&lt;br /&gt;spit on ANSI/ISO Standards with "SET QUOTED_IDENTIFIER OFF", etc.?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You need help you cannot get on a newsgroup.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4897320867948790986?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4897320867948790986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4897320867948790986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4897320867948790986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4897320867948790986'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/stored-procedure-returns-duplicates_22.html' title='Stored procedure returns duplicates'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-1465611812423807622</id><published>2007-04-12T13:31:00.000-04:00</published><updated>2007-04-12T13:32:31.766-04:00</updated><title type='text'>Month Year Date Comparison</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; am running into a slight issue with a month year comparison.  I &lt;br /&gt;wrote q SP thats user-input driven. User selects a Start Month, Start &lt;br /&gt;Year and an End Month and End Year.  The database that houses the &lt;br /&gt;information has month and year columns. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Example: &lt;br /&gt;Name  Month Year &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Me 1 2006 &lt;br /&gt;You 1 2006 &lt;br /&gt;Us 3 2005 &lt;br /&gt;He 5 2007 &lt;br /&gt;She 6 2005 &lt;br /&gt;It 7 2006 &lt;br /&gt;We 12 2005 &lt;br /&gt;They 11 2005 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The query looks like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select cust.name,  CASE rev.[month] &lt;br /&gt;        WHEN '01' THEN 'January' &lt;br /&gt;        WHEN '02' THEN 'February' &lt;br /&gt;        WHEN '03' THEN 'March' &lt;br /&gt;        WHEN '04' THEN 'April' &lt;br /&gt;        WHEN '05' THEN 'May' &lt;br /&gt;        WHEN '06' THEN 'June' &lt;br /&gt;        WHEN '07' THEN 'July' &lt;br /&gt;        WHEN '08' THEN 'August' &lt;br /&gt;        WHEN '09' THEN 'September' &lt;br /&gt;        WHEN '10' THEN 'October' &lt;br /&gt;        WHEN '11' THEN 'November' &lt;br /&gt;        WHEN '12' THEN 'December' &lt;br /&gt;END AS [Month], rev.year &lt;br /&gt;from rev &lt;br /&gt;        inner join cust ON rev.name = cust.name &lt;br /&gt;where (rev.name = @ter) AND (rev.month &gt;= @start_month)  AND (rev.year &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;= @start_year) AND  (rev.month &lt;= @end_month) AND (rev.year &lt;= &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@end_year) &lt;br /&gt;group by blah blah blah &lt;br /&gt;order by blay blah blah &lt;br /&gt;&lt;br /&gt;This works great until they span years. &lt;br /&gt;Example: &lt;br /&gt;Start Month = 11 &lt;br /&gt;Start Year = 2005 &lt;br /&gt;End Month = 2 &lt;br /&gt;End Year = 2006 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any ideas on how to make this work? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;This design flaw is called attribute splitting.  A date is a single &lt;br /&gt;unit of information, but you have put it into multiple columns. We can &lt;br /&gt;fake it for your current problem, but you need to learn to use &lt;br /&gt;temproal data types in SQL -- this is not 1950's COBOL any more, which &lt;br /&gt;is how you are writing code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-1465611812423807622?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/1465611812423807622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=1465611812423807622' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1465611812423807622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1465611812423807622'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/month-year-date-comparison.html' title='Month Year Date Comparison'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-4424447454475732288</id><published>2007-04-11T14:31:00.000-04:00</published><updated>2007-04-11T14:37:20.036-04:00</updated><title type='text'>Convert *= / =* to outer joins (ANSI compliant)</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm working on converting *= and =* to 'left outer join' and 'right outer &lt;br /&gt;join'. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I noticed the difference in behavior between the =* and the phrase "right &lt;br /&gt;outer join" and between *=  and 'left outer join'. The result set is &lt;br /&gt;different. Here is an example: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select a.au_id, b.title, c.qty &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;from titleauthor a, titles b, sales c &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;where (a.title_id =* b.title_id) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and (a.title_id =* c.title_id) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I try to conver the above to: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; select a.au_id, b.title, c.qty &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;from titleauthor a &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;right outer join titles b &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;on (a.title_id = b.title_id ) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;right outer join sales c &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;on (a.title_id = c.title_id ) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first results into 391 rows in pubs database of sql-server 2000 and the &lt;br /&gt;second produces 34 rows. It seems not that straight forward to convert. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The question is: If I want to get 391 row, what should I change/add in the &lt;br /&gt;second sql statement? &lt;br /&gt;&lt;br /&gt; Thank you. Appreciate your help. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;pre&gt;There is no simple answer because the old proprietary *=, +=, OUTER &lt;br /&gt;&amp;lt;tbl name&amp;gt;, (+) syntaxes all behaved a little differently.  There were &lt;br /&gt;a lot of weird tricks to work around the fixed orders of execution and &lt;br /&gt;so forth. &lt;br /&gt;&lt;br /&gt;I am also not sure how to handle a "HAVING  x *= y" clause, which old &lt;br /&gt;Sybase people used to write. And then nesting subqueries could mess up &lt;br /&gt;things.  But if you understand how the ANSI syntax works, then you can &lt;br /&gt;take the **intent** of the old code and re-write the statements pretty &lt;br /&gt;quickly. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is how OUTER JOINs work in SQL-92.  Assume you are given: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Table1       Table2 &lt;br /&gt; a   b        a   c &lt;br /&gt; ======       ====== &lt;br /&gt; 1   w        1   r &lt;br /&gt; 2   x        2   s &lt;br /&gt; 3   y        3   t &lt;br /&gt; 4   z &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and the outer join expression: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Table1 &lt;br /&gt; LEFT OUTER JOIN &lt;br /&gt; Table2 &lt;br /&gt; ON Table1.a = Table2.a      &amp;lt;== join condition &lt;br /&gt;    AND Table2.c = 't';      &amp;lt;== single table condition &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We call Table1 the "preserved table" and Table2 the "unpreserved &lt;br /&gt;table" in the query.  What I am going to give you is a little &lt;br /&gt;different, but equivalent to the ANSI/ISO standards. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) We build the CROSS JOIN of the two tables.  Scan each row in the &lt;br /&gt;result set. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) If the predicate tests TRUE for that row, then you keep it. You &lt;br /&gt;also remove all rows derived from it from the CROSS JOIN &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) If the predicate tests FALSE or UNKNOWN for that row, then keep the &lt;br /&gt;columns from the preserved table, convert all the columns from the &lt;br /&gt;unpreserved table to NULLs and remove the duplicates. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So let us execute this by hand: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Let @ = passed the first predicate &lt;br /&gt; Let * = passed the second predicate &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Table1 CROSS JOIN Table2 &lt;br /&gt; a   b        a   c &lt;br /&gt; ========================= &lt;br /&gt; 1   w       1   r @ &lt;br /&gt; 1   w       2   s &lt;br /&gt; 1   w       3   t * &lt;br /&gt; 2   x       1   r &lt;br /&gt; 2   x       2   s @ &lt;br /&gt; 2   x       3   t * &lt;br /&gt; 3   y       1   r &lt;br /&gt; 3   y       2   s &lt;br /&gt; 3   y       3   t @* &amp;lt;== the TRUE set &lt;br /&gt; 4   z       1   r &lt;br /&gt; 4   z       2   s &lt;br /&gt; 4   z       3   t * &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Table1 LEFT OUTER JOIN Table2 &lt;br /&gt; a   b        a   c &lt;br /&gt; ========================= &lt;br /&gt; 3   y     3      t      &amp;lt;= only TRUE row &lt;br /&gt; ----------------------- &lt;br /&gt; 1   w     NULL   NULL   Sets of duplicates &lt;br /&gt; 1   w     NULL   NULL &lt;br /&gt; 1   w     NULL   NULL &lt;br /&gt; ----------------------- &lt;br /&gt; 2   x     NULL   NULL &lt;br /&gt; 2   x     NULL   NULL &lt;br /&gt; 2   x     NULL   NULL &lt;br /&gt; 3   y     NULL   NULL  &amp;lt;== derived from the TRUE set - Remove &lt;br /&gt; 3   y     NULL   NULL &lt;br /&gt; ----------------------- &lt;br /&gt; 4   z     NULL   NULL &lt;br /&gt; 4   z     NULL   NULL &lt;br /&gt; 4   z     NULL   NULL &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the final results: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Table1 LEFT OUTER JOIN Table2 &lt;br /&gt; a   b        a   c &lt;br /&gt; ========================= &lt;br /&gt; 1   w     NULL   NULL &lt;br /&gt; 2   x     NULL   NULL &lt;br /&gt; 3   y     3      t &lt;br /&gt; 4   z     NULL   NULL &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The basic rule is that every row in the preserved table is represented &lt;br /&gt;in the results in at least one result row. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There are limitations and very serious problems with the extended &lt;br /&gt;equality version of an outer join used in some diseased mutant &lt;br /&gt;products.  Consider the two Chris Date tables &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Suppliers        SupParts &lt;br /&gt; supno             supno partno qty &lt;br /&gt; =========        ============== &lt;br /&gt; S1               S1   P1    100 &lt;br /&gt; S2               S1   P2    250 &lt;br /&gt; S3               S2   P1    100 &lt;br /&gt;                  S2   P2    250 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and let's do an extended equality outer join like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT * &lt;br /&gt;  FROM Supplier, SupParts &lt;br /&gt; WHERE Supplier.supno *= SupParts.supno &lt;br /&gt;   AND qty &amp;lt; 200; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If I do the outer first, I get: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Suppliers LOJ SupParts &lt;br /&gt; supno supno partno qty &lt;br /&gt; ======================= &lt;br /&gt; S1     S1   P1    100 &lt;br /&gt; S1     S1   P2    250 &lt;br /&gt; S2     S2   P1    100 &lt;br /&gt; S2     S2   P2    250 &lt;br /&gt; S3   NULL  NULL   NULL &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Then I apply the (qty &amp;lt; 200) predicate and get &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Suppliers LOJ SupParts &lt;br /&gt; supno supno partno qty &lt;br /&gt; =================== &lt;br /&gt; S1   S1   P1    100 &lt;br /&gt; S2   S2   P1    100 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Doing it in the opposite order &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Suppliers LOJ SupParts &lt;br /&gt; supno supno partno qty &lt;br /&gt; =================== &lt;br /&gt; S1   S1   P1    100 &lt;br /&gt; S2   S2   P1    100 &lt;br /&gt; S3   NULL NULL  NULL &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sybase does it one way, Oracle does it the other and Centura (nee &lt;br /&gt;Gupta) lets you pick which one -- the worst of both non-standard &lt;br /&gt;worlds!  In SQL-92, you have a choice and can force the order of &lt;br /&gt;execution. Either do the predicates after the join ... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT * &lt;br /&gt;   FROM Supplier &lt;br /&gt;        LEFT OUTER JOIN &lt;br /&gt;        SupParts &lt;br /&gt;        ON Supplier.supno = SupParts.supno &lt;br /&gt; WHERE qty &amp;lt; 200; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; ... or do it in the joining: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT * &lt;br /&gt;  FROM Supplier &lt;br /&gt;       LEFT OUTER JOIN &lt;br /&gt;       SupParts &lt;br /&gt;       ON Supplier.supno = SupParts.supno &lt;br /&gt;          AND qty &amp;lt; 200; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Another problem is that you cannot show the same table as preserved &lt;br /&gt;and unpreserved in the extended equality version, but it is easy in &lt;br /&gt;SQL-92.  For example to find the students who have taken Math 101 and &lt;br /&gt;might have taken Math 102: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; SELECT C1.student, C1.math, C2.math &lt;br /&gt;  FROM (SELECT * FROM Courses WHERE math = 101) AS C1 &lt;br /&gt;       LEFT OUTER JOIN &lt;br /&gt;       (SELECT * FROM Courses WHERE math = 102) AS C2 &lt;br /&gt;       ON C1.student = C2.student; &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-4424447454475732288?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/4424447454475732288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=4424447454475732288' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4424447454475732288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/4424447454475732288'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/convert-to-outer-joins-ansi-compliant.html' title='Convert *= / =* to outer joins (ANSI compliant)'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-7078929829649403129</id><published>2007-04-10T15:38:00.000-04:00</published><updated>2007-04-10T15:40:45.034-04:00</updated><title type='text'>need help switching a boolean value</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;what i want to acheieve is the following, in my table i have an "isactive" &lt;br /&gt;field, i want to create a sql line something like &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;update tblProducts set isactive = NOT isactive where productID=123....but it &lt;br /&gt;doesnt work.. is there any syntax that handles this in sql? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  in my table i have an "isactive" field [sic: fields and columns are TOTALLY different concepts!!!], I want to create a SQL line [sic: statement? that makes no sense!!] something like this: &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Do you every read ISO Standards and know not to use "tbl" affixes? &lt;br /&gt;&lt;br /&gt;UPDATE Products &lt;br /&gt;  SET isactive -- assembly lamnguage flag in SQL !!! &lt;br /&gt;       = NOT isactive &lt;br /&gt; WHERE product_id = 123; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;....but it doesn't work &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DUH!!  If you had bothered to read ANY SQL book before posting, you &lt;br /&gt;would know we have no Boolean data types in SQL.  If you had a better &lt;br /&gt;education in math or RDBMS, you would know why. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Newsgroups are a bad place to get a basic education.  We will give you &lt;br /&gt;kludges to get rid of you because of your stupid questions, but they &lt;br /&gt;will not make you a good programmer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7078929829649403129?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7078929829649403129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7078929829649403129' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7078929829649403129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7078929829649403129'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/need-help-switching-boolean-value.html' title='need help switching a boolean value'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3775893476190995856</id><published>2007-04-10T15:32:00.000-04:00</published><updated>2007-04-10T15:33:49.124-04:00</updated><title type='text'>SQL: how to convert time from GMT to EST</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;In my Database, all date and time are stored in GMT, however, when it &lt;br /&gt;is displayed, I need them in EST. How can this be done with Daylight &lt;br /&gt;saving time taken into account as well? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; In my Database, all date and time are stored in GMT,  .. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Interesting. GMT has not existed for a VERY LONG TIME!  Google iot, so &lt;br /&gt;you will not look so far behind.  Did you mean UTC and just do not &lt;br /&gt;bother to learn this decade's technology? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; How can this be done with Daylight Saving Time taken into account as well? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is called "local lawful time" and it varies quite a bit.  Set up &lt;br /&gt;a copy of the Standard SQL temporal information tables that MS has not &lt;br /&gt;bothered with yet.  Then set up VIEWs and use them.  These auxiliary &lt;br /&gt;tables will have (start_time, end_time, displacement off of UTC) &lt;br /&gt;columns for the DST.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3775893476190995856?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3775893476190995856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3775893476190995856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3775893476190995856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3775893476190995856'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/sql-how-to-convert-time-from-gmt-to-est.html' title='SQL: how to convert time from GMT to EST'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-3766661256853633188</id><published>2007-04-09T14:27:00.000-04:00</published><updated>2007-04-09T14:28:09.848-04:00</updated><title type='text'>Data type in audit record</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I want my application to audit any data changes (update, insert, &lt;br /&gt;delete) made by the users.  Rather than have an audit table mirroring &lt;br /&gt;each user table, I'd prefer to have a generic structure which can log &lt;br /&gt;anything.  This is what I've come up with: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;TABLE: audit_record &lt;br /&gt;*audit_record_id (uniqueidentifier, auto-assign, PK) - unique &lt;br /&gt;idenfiier of the audit record &lt;br /&gt;table_name (varchar) - name of the table where the action (insert/ &lt;br /&gt;update/delete) was made &lt;br /&gt;pk_value (varchar) - primary key of the changed record.  If the PK &lt;br /&gt;itself has changed, this will store the old value. &lt;br /&gt;user_id (varchar) - user who changed the record &lt;br /&gt;date (datetime) - date/time at which the change was made &lt;br /&gt;action (int) - 0, 1 or 2 (insert, update, delete) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;TABLE: audit_column &lt;br /&gt;*audit_record_id (uniqueidentifier, composite PK) - FK to &lt;br /&gt;cdb_audit_record table &lt;br /&gt;*column_name (varchar, composite PK) - name of the column with changed &lt;br /&gt;data &lt;br /&gt;new_value (text?) - value after the change &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So every column which changes has its new value logged individually in &lt;br /&gt;the audit_column table.  However, I'm not sure what data type the &lt;br /&gt;new_value column should have. The obvious answer (to me) is text, as &lt;br /&gt;that can handle any necessary data type with the appropriate &lt;br /&gt;conversion (we don't store any binary data).  However, this table is &lt;br /&gt;going to grow to millions of records and I'm not sure what the &lt;br /&gt;performance implications of a text column will be, particularly given &lt;br /&gt;that the actual data stored in it will almost always be tiny. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any thoughts/recommendations/criticism would be greatly appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I want my application to audit any data changes (update, insert, delete) made by the users.  Rather than have an audit table mirroring each user table, I'd prefer to have a generic structure which can log anything. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any chance you might post DDL instead of your personal pseudo-code? &lt;br /&gt;And I hope you know that auto-numbering is not a relational key. &lt;br /&gt;Finally, Google "EAV design flaw" for tens of thousands of words on &lt;br /&gt;why this approach stinks.  There is no such magical shape shifting &lt;br /&gt;table in RDBMS.   Data Versus metadata, etc.?  Freshman database &lt;br /&gt;course, 3rd week of the quarter? &lt;br /&gt;&lt;br /&gt;While you might like this kludge your accountants and auditors will &lt;br /&gt;not.  NEVER keep audit trails on the same database or even the same &lt;br /&gt;hardware as the database. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Any thoughts/recommendations/criticism would be greatly appreciated. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Look at third party tools that follow the law and get a basic dat &lt;br /&gt;modeling book.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-3766661256853633188?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/3766661256853633188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=3766661256853633188' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3766661256853633188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/3766661256853633188'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/data-type-in-audit-record.html' title='Data type in audit record'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-7972178693905295139</id><published>2007-04-09T14:25:00.000-04:00</published><updated>2007-04-09T14:28:31.420-04:00</updated><title type='text'>Newbie: a query to get back the closest number to user input number.</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a situation where I need to return the name and salary of an &lt;br /&gt;employee closest to the salary entered by the user. &lt;br /&gt;&lt;br /&gt;Is there a "Nearest" or "Closest" type of operator in sql that will &lt;br /&gt;help me instantly get the row that is closest to an arbitrary number? &lt;br /&gt;If not, can anyone help me with an approach to this type of single &lt;br /&gt;table problem? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Much appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  Is this what you meant to post? &lt;br /&gt;&lt;br /&gt;CREATE TABLE Personnel &lt;br /&gt;(emp_name CHAR(25) NOT NULL PRIMARY KEY, &lt;br /&gt; salary_amt DECIMAL (10,2) NOT NULL &lt;br /&gt;    CHECK (salary_amt &gt; 0.00)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Try something like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT emp_name, salary_amt, @my_salary AS search_salary &lt;br /&gt;  FROM Personnel AS P &lt;br /&gt; WHERE ABS(P.salary_amt - @my_salary) &lt;br /&gt;    = (SELECT MIN (ABS(P2.salary_amt - @my_salary)) &lt;br /&gt;         FROM Personnel AS P2); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The closest salary might be higher or lower than the search value, so &lt;br /&gt;you need ABS().  In the real world, there will be a lot of ties, since &lt;br /&gt;most companies have salary schedules rather than odd.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7972178693905295139?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7972178693905295139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7972178693905295139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7972178693905295139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7972178693905295139'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/04/newbie-query-to-get-back-closest-number.html' title='Newbie: a query to get back the closest number to user input number.'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-1125468553908214396</id><published>2007-03-31T13:39:00.000-04:00</published><updated>2007-03-31T13:50:43.395-04:00</updated><title type='text'>Update Status Field after Expiry Date</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Consider the following table &lt;br /&gt;&lt;br /&gt;Customer &lt;br /&gt;custId char(10) &lt;br /&gt;accountExpiryDate datetime &lt;br /&gt;accountStatus bit &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, I want to update the accountStatus to False as soon as the &lt;br /&gt;current date becomes accountExpiryDate. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I think it can be done using "SQL Agent" but my webhost doesnt provide &lt;br /&gt;me access to that. I have access only to the Query Analyzer. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Consider the following table &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Where is it?  Please post DDL, so that people do not have to guess &lt;br /&gt;what the keys, constraints, Declarative Referential Integrity, data &lt;br /&gt;types, etc. in your schema are. Sample data is also a good idea, along &lt;br /&gt;with clear specifications.  It is very hard to debug code when you do &lt;br /&gt;not let us see it.  Here is my guess: &lt;br /&gt;&lt;br /&gt; CREATE TABLE Customers &lt;br /&gt;(cust_id CHAR(10) NOT NULL PRIMARY KEY, --wild guess &lt;br /&gt; acctexpiry_date DATETIME NOT NULL, &lt;br /&gt;  ..); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notice I dropped the redundant BIT column.  Some newbie actually used &lt;br /&gt;a proprietary, low-level BIT data type.  You need to fix that at once &lt;br /&gt;and teach the guy that SQL has no BOOLEAN data types -- that is just &lt;br /&gt;sooooo fundamental! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Now, I want to update the account_status to FALSE as soon AS the current date becomes accountexpiry_date. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Just like you would do this in a punch card system 50 years ago! &lt;br /&gt;Running updates to physical storage every day?  You are missing the &lt;br /&gt;fundamental concepts of RDBMS in this design.  Each row of a table is &lt;br /&gt;a fact that should stand by itself.  Use a VIEW not an assembly &lt;br /&gt;language bit flag!! &lt;br /&gt;&lt;br /&gt;CREATE VIEW ActiveCustomers (..) &lt;br /&gt; AS &lt;br /&gt;SELECT cust_id, acctexpiry_date, .. &lt;br /&gt;  FROM Customers &lt;br /&gt; WHERE CURRENT_TIMESTAMP &lt; acctexpiry_date; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And then you need to consider how much history and account status &lt;br /&gt;codes you want.  Do you need to design an acct_status code?  Etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-1125468553908214396?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/1125468553908214396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=1125468553908214396' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1125468553908214396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/1125468553908214396'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/03/update-status-field-after-expiry-date.html' title='Update Status Field after Expiry Date'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-7658430386557133883</id><published>2007-03-22T12:29:00.000-04:00</published><updated>2007-03-22T12:30:28.588-04:00</updated><title type='text'>Incorrect syntax near the keyword 'As'</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm trying to complete an If, Then statement within a script that I put &lt;br /&gt;together, and I keep getting an "Incorrect syntax near the keyword 'As'" &lt;br /&gt;error toward the end of the statement. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The whole statement says that if you are taking the payroll codes from the &lt;br /&gt;benefit table, then provide the payroll code's description such "health &lt;br /&gt;insurance" or "dental insurance". &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The very beginning of my clause, of course, says "SELECT ... CASE &lt;br /&gt;UPR30300.PAYROLCD WHEN 'SC2HF' THEN UPR40800.DSCRIPTN &lt;br /&gt;WHEN 'SC2LE' THEN UPR40800.DSCRIPTN &lt;br /&gt;WHEN 'SC2LS' THEN UPR40800.DSCRIPTN &lt;br /&gt;WHEN 'SC2LC' THEN UPR40800.DSCRIPTN &lt;br /&gt;WHEN 'SC2LF' THEN UPR40800.DSCRIPTN &lt;br /&gt;ELSE 0 END As [Payroll Description] &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There must be something wrong with the ELSE portion.  I tried to fix it, by &lt;br /&gt;saying ELSE '' END As [Payroll Description].  But, I got the same error. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What am I doing wrong, and how can I fix this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Having blanks inside a column name is a bad idea, since the name will &lt;br /&gt;not port to other languages, is very easy to mis-type and messes up &lt;br /&gt;the data dictionary. You also used the proprietary square brackets &lt;br /&gt;instead of the proper double quotes. &lt;br /&gt;&lt;br /&gt;You can make your code a lot easier to read without the extra WHEN &lt;br /&gt;clauses.  A CASE expression has one and only one data type.  You need &lt;br /&gt;to be sure that the THEN clauses are all the same data type. That can &lt;br /&gt;be done with implicit promotion or use a CAST() function. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CASE &lt;br /&gt;WHEN UPR30300.payrol_cd &lt;br /&gt;     IN ('0SC2HF', 'SC2LE', 'SC2LS', 'SC2LC') &lt;br /&gt;THEN UPR40800.dscriptn &lt;br /&gt;ELSE '{{Unknown}}' AS payroll_description&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-7658430386557133883?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/7658430386557133883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=7658430386557133883' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7658430386557133883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/7658430386557133883'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/03/incorrect-syntax-near-keyword-as.html' title='Incorrect syntax near the keyword &apos;As&apos;'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-6735906102053391137</id><published>2007-03-22T12:19:00.000-04:00</published><updated>2007-03-22T12:24:40.281-04:00</updated><title type='text'>SQL Conundrum</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have the following SQL schema&lt;br /&gt;&lt;br /&gt;Bookings&lt;br /&gt;-------------&lt;br /&gt;BookID&lt;br /&gt;Hours&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;BookingStatus&lt;br /&gt;---------------------&lt;br /&gt;BookStatusID&lt;br /&gt;BookingId&lt;br /&gt;StatusID&lt;br /&gt;UserId&lt;br /&gt;Date&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Statues&lt;br /&gt;-----------&lt;br /&gt;StatusID&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Statuses included Created, Covered, Cancelled, Not Covered, To Be&lt;br /&gt;Arranged, etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The BookingStatus table contains a history of the statuses a booking&lt;br /&gt;goes through. Whenever a user updates the status of a booking, a new&lt;br /&gt;record is inserted into the Booking Status with the corresponding&lt;br /&gt;data.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm trying to create a report to show the number of bookings each user&lt;br /&gt;has covered over a given time period. However, i only want to count&lt;br /&gt;bookings that are still covered (i.e. have not been cancelled since&lt;br /&gt;they were covered) and i don't want it to count bookings that have&lt;br /&gt;been covered more than once. If it did, a user would be credited for&lt;br /&gt;covering an individual booking more than once.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In other words, i need to fetch only the top 1 status of each booking&lt;br /&gt;and count only those that are covered, if you see what i mean!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I could record the current status of the booking in my Bookings table,&lt;br /&gt;but i'm worried about data integrity and keeping the booking status&lt;br /&gt;consistant.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anyone got any bright ideas about how i can either design my schema&lt;br /&gt;better, or come up with an efficient SQL query to select my report? I&lt;br /&gt;also need to sum the hours each user has covered, as well as a count&lt;br /&gt;of bookings covered.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Many thanks for any suggestions&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Many thanks for any suggestions&lt;br /&gt;&lt;br /&gt;Here is a "cut &amp; paste" on history tables.  In your case, I would also look at my article on Transition Constraints at &lt;a href="http://www.dbazine.com"&gt;www.dbazine.com&lt;/a&gt; for more ideas.&lt;br /&gt;&lt;br /&gt;===============&lt;br /&gt;The start and stop times are what you should have been catching in the first place and not the computed hours. Think raw data and single facts when designing a table. Let me use a history table for price changes. The fact to store is that a price had a duration:&lt;br /&gt;&lt;br /&gt;CREATE TABLE PriceHistory (upc CHAR(13) NOT NULL&lt;br /&gt;REFERENCES Inventory(upc),&lt;br /&gt;start_date DATE NOT NULL,&lt;br /&gt;end_date DATE, -- null means current&lt;br /&gt;CHECK(start_date &lt;&gt; 0.0000),&lt;br /&gt;etc.);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You actually needs more checks to assure that the start date is at&lt;br /&gt;00:00 and the end dates is at 23:59:59.999 Hrs. You then use a&lt;br /&gt;BETWEEN predicate to get the appropriate price.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT ..&lt;br /&gt;FROM PriceHistory AS H, Orders AS O&lt;br /&gt;WHERE O.sales_date BETWEEN H.start_date&lt;br /&gt;AND COALESCE (end_date, CURRENT_TIMESTAMP);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It is also a good idea to have a VIEW with the current data:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW CurrentPrices (..)&lt;br /&gt;AS&lt;br /&gt;SELECT ..&lt;br /&gt;FROM PriceHistory&lt;br /&gt;WHERE end_date IS NULL;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-6735906102053391137?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/6735906102053391137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=6735906102053391137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6735906102053391137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/6735906102053391137'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2007/03/sql-conundrum.html' title='SQL Conundrum'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438236533229506</id><published>2006-11-24T10:30:00.000-05:00</published><updated>2006-11-24T10:32:45.543-05:00</updated><title type='text'>While loop?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;So I am just starting to learn how to use Database.  I need the help of a SQL &lt;br /&gt;guru! I have these three tables: &lt;br /&gt;CREATE TABLE SB3_ScheduleChange &lt;br /&gt;( &lt;br /&gt;emp_num         EmpNumType:nvarchar(7)   NOT NULL   PRIMARY KEY, &lt;br /&gt;Monday          char(35)                 NULL, &lt;br /&gt;Tuesday         char(35)                 NULL, &lt;br /&gt;Wednesday       char(35)                 NULL, &lt;br /&gt;Thursday                        char(35)                 NULL, &lt;br /&gt;Friday          char(35)                 NULL, &lt;br /&gt;Saturday                         char(35)                NULL, &lt;br /&gt;Sunday          char(35)                 NULL, &lt;br /&gt;Name            char(35)                 NOT NULL; &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;CREATE TABLE SB3_ScheduleChange &lt;br /&gt;( &lt;br /&gt;emp_num                              EmpNumType:nvarchar(7)   NOT NULL   PRIMARY KEY, &lt;br /&gt;sched_type_id        nt,                         NOT NULL, &lt;br /&gt;start_date                           DateType:datetime   NOT NULL, &lt;br /&gt;end_date                             DateType:datetime   NOT NULL, &lt;br /&gt;comments                             varchar(8000)               NULL, &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE SB3_ScheduleType &lt;br /&gt;( &lt;br /&gt;sched_type_id   int,                     NOT NULL                PRIMARY KEY, &lt;br /&gt;reason          char(20)                 NULL, &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am trying to come up with a query that will iterate through each employee &lt;br /&gt;with the emp_num primary key in the emp_shcedule table.  I would like the &lt;br /&gt;iteration to check if the employee has an exception or "change" from their &lt;br /&gt;regular default schedule in the table emp_schedule checking it against the &lt;br /&gt;"SB3_ScheduleChange" table. And if the query finds a difference in schedule &lt;br /&gt;to update or insert it into that employees default schedule until the change &lt;br /&gt;is over on a certain date.  My problem is I am new to SQL and I dont know how &lt;br /&gt;to do this.  Do I need a Calendar table?  Use a while loop?  Any examples, &lt;br /&gt;help, or suggestions would be very much appreciated.  Not that this will help &lt;br /&gt;but here are some queries I have come up with.  Just dont know how to tie it &lt;br /&gt;all together. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This would list name, emp_num, sched_type_id, for each employee who has &lt;br /&gt;A schedule type difference.  Query shows every employee with a schedule type &lt;br /&gt;difference. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT es.Name, es.emp_num, sc.sched_type_id &lt;br /&gt;        FROM emp_schedule AS es JOIN SB3_ScheduleChange AS sc &lt;br /&gt;                ON(es.emp_num = sc.emp_num) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;List name, emp_num of employees that are not assigned to any schedule &lt;br /&gt;change. Query shows every employee without a schedule type difference. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT name, emp_num &lt;br /&gt;        FROM emp_schedule AS es &lt;br /&gt;        WHERE NOT EXISTS &lt;br /&gt;                (SELECT emp_num &lt;br /&gt;                        FROM SB3_ScheduleChange AS sc &lt;br /&gt;                        WHERE es.emp_num = sc.emp_num); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And if necessary a Calendar CREATE TABLE.  But once again I am not sure. &lt;br /&gt;  CREATE TABLE dbo.SB3_Calender &lt;br /&gt;( &lt;br /&gt;        ActualDate      DATETIME        NOT NULL        PRIMARY KEY, &lt;br /&gt;        MonthName       CHAR(15)        NULL, &lt;br /&gt;        DayNumber       INT             NULL, &lt;br /&gt;        YearNumber      INT             NULL, &lt;br /&gt;        DayOfWeek       CHAR(15)        NULL &lt;br /&gt;              CHECK (DayOfWeek IN ('Sunday', 'Monday', 'Tuesday', &lt;br /&gt;              'Wednesday','Thursday','Friday','Saturday')), &lt;br /&gt;        DayType         CHAR(15)        NULL &lt;br /&gt;              CHECK ( DayType IN ('Business','Weekend','Holiday')), &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET NOCOUNT ON &lt;br /&gt;DECLARE @Counter        INT &lt;br /&gt;DECLARE @ActualDate     DATETIME &lt;br /&gt;DECLARE @FirstDate      DATETIME &lt;br /&gt;SET @Counter = 1 &lt;br /&gt;SET @FirstDate = '1/1/2006' &lt;br /&gt;SET @ActualDate = @FirstDate &lt;br /&gt;      WHILE @Counter &lt; 1096 &lt;br /&gt;BEGIN &lt;br /&gt;INSERT INTO Calender (ActualDate) &lt;br /&gt;      values(@ActualDate) &lt;br /&gt;SET @ActualDate = DATEADD(day, @Counter, @FirstDate) &lt;br /&gt;SET @Coutner = @Counter + 1 &lt;br /&gt;END &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET DayOfWeek = DateName(DW, ActualDate) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET DayNumber = DateName(DD,ActualDate) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET MonthName = DateName(MM,ActualDate) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET YearNumber = DateName(YY,ActualDate) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET DayType = 'Business' &lt;br /&gt;WHERE DayOfWeek &lt;&gt; 'Saturday' AND DayOfWeek &lt;&gt; 'Sunday' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET DayType = 'Weekend' &lt;br /&gt;WHERE DayOfWeek = 'Saturday' OR DayOfWeek = 'Sunday' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Calender &lt;br /&gt;SET DayType = 'Holiday' &lt;br /&gt;WHERE (MonthName ='January' AND DayNumber = 1 ) OR &lt;br /&gt;      (MonthName ='July' AND DayNumber = 4) OR &lt;br /&gt;      (MonthName ='December' AND DayNumber = 25) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; So I am just starting to learn how to use Database. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) What you are doing is mimicing a paper schedule form, not designing &lt;br /&gt;a normalized schema. &lt;br /&gt;&lt;br /&gt;2) data element names like  the days of the week are values and not &lt;br /&gt;attributes.  Tha tis the output of a cross tabs report, not a table. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Column names like "sched_type_id" are absurd; an attribute can a key &lt;br /&gt;(identifier, points to a unique *entity* in the data model) or a type &lt;br /&gt;(non-key *attribute*, holds a value) but NEVER both. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4) You are still thinking about procedural code instead of declarative &lt;br /&gt;programming and data.  YOu have designed a magentic tape file merge, &lt;br /&gt;complete with record at a time processing.  Welcom to 1957! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why not something like this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE PersonnelSchedules &lt;br /&gt; (emp_num  CHAR(7)  NOT NULL &lt;br /&gt;    REFERENCES Personnel(emp_num) &lt;br /&gt;    ON UPDATE CASCADE &lt;br /&gt;    ON DELETE CASCADE, &lt;br /&gt; activity_date  DATETIME NOT NULL, &lt;br /&gt; PRIMARY KEY (emp_num, activity_date), &lt;br /&gt; activity_code INTEGER NOT NULL &lt;br /&gt;   CHECK (activity_code IN (...)), &lt;br /&gt; ..); , &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am assuming one activity per day; if not this can be modified by &lt;br /&gt;adding an activity number.  You might need other attributes, but I &lt;br /&gt;don't know you business rules. A single fact should be modeled witha &lt;br /&gt;single row in a single table, not split all over the schema. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I am trying to come up with a query that will iterate through each employee with the emp_num primary key in the emp_shcedule table.  I would like the iteration to check if the employee has an exception or "change" from their regular default schedule in the table emp_schedule checking it against the "SB3_ScheduleChange" table. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why not go to the PersonnelSchedules and make this change, without &lt;br /&gt;storing it in multiple locations?  If you need to mark something as a &lt;br /&gt;schedule change, then add a column for that  attribute to the table. &lt;br /&gt;&lt;br /&gt;When you get a new guy, fill out his schedule for 5-10 years in &lt;br /&gt;advance.  It will use less disk space than a hi-res employee badge &lt;br /&gt;photograph.  Now you can use a VIEW to get the weekly schedules, you &lt;br /&gt;can do manpower projections, etc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Most queries are easy if you have the right DDL.  You should never use &lt;br /&gt;a cursor in your SQL; we had to in the old days because we did not have &lt;br /&gt;CTEs, CASE expressions, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438236533229506?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438236533229506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438236533229506' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438236533229506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438236533229506'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/while-loop.html' title='While loop?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438201035127210</id><published>2006-11-24T10:24:00.000-05:00</published><updated>2006-11-24T10:26:50.560-05:00</updated><title type='text'>complex(?) query</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm a novice sql writer and need some help in writing a query to &lt;br /&gt;extract applicable data from the following table (titled EMPLOYEE): &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- &lt;br /&gt;ID_NUMBER       CODE    DATE &lt;br /&gt;------------------              ---------        -------- &lt;br /&gt;12                      VO      20060914 &lt;br /&gt;12                      XD      20060913 &lt;br /&gt;12                      AD      20060912 &lt;br /&gt;12                      WR      20060911 &lt;br /&gt;12                      AT      20060910 &lt;br /&gt;45                      VO      20060914 &lt;br /&gt;45                      XR      20060913 &lt;br /&gt;45                      AT      20060912 &lt;br /&gt;45                      AD      20060911 &lt;br /&gt;45                      AT      20060910 &lt;br /&gt;78                      AD      20060914 &lt;br /&gt;78                      AT      20060913 &lt;br /&gt;78                      VO      20060912 &lt;br /&gt;78                      AD      20060911 &lt;br /&gt;78                      AT      20060910 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need to select ID_NUMBER &lt;br /&gt;from EMPLOYEE &lt;br /&gt;where CODE = 'VO' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;caveat:  I only want the ID_NUMBER(s) where the CODE = 'VO' &lt;br /&gt;and the previous CODE (by DATE) = 'AD' &lt;br /&gt;or the previous CODE (by DATE) = 'AD' with any CODE in between &lt;br /&gt;except 'AT'; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;E.g., in the above example, the appropriate code should select &lt;br /&gt;ID_NUMBER(s) 12 and 78 because &lt;br /&gt;1. a VO code exists &lt;br /&gt;2. an AD code (by DATE) precedes it &lt;br /&gt;3. although 'AD' does not come immediately before 'VO' (in the &lt;br /&gt;case of ID_NUMBER 12) 'AT' cannot be found in between &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I hope I haven't confused anyone.  Any help would be appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;I'm a novice sql writer and need some help in writing a query to extract applicable data from the following table (titled EMPLOYEE): &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First, let's clean up your missing DDL.  The table name should tell us &lt;br /&gt;what set of entities is modeled in the table; do you really have one &lt;br /&gt;employee?  Small firm!  Try Personnel -- the collective name of the set &lt;br /&gt;or something that tells us what the set is.  Code is too vague -- &lt;br /&gt;postal code?  Date is both too vague *and* a reserved word.  A name &lt;br /&gt;like "id_number" is also uselessly general; emp_id would be a better &lt;br /&gt;choice. Since you did not post DDL, we have to guess at constaints and &lt;br /&gt;keys.  A skeleton of what you need is something like this: &lt;br /&gt;&lt;br /&gt;CREATE TABLE PersonnelActions &lt;br /&gt;(emp_id INTEGER NOT NULL, &lt;br /&gt; action_date action_dateTIME DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt; PRIMARY KEY (emp_id, foobar_date), &lt;br /&gt; action_code CHAR(2) NOT NULL &lt;br /&gt;    CHECK (foobar_code IN ('VO', 'XD')) &lt;br /&gt;); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You need to read a book on data modeling and ISO-11179 rules for names. &lt;br /&gt;I would also look up the use of UPPERCASE for names -- it is the worst &lt;br /&gt;way to code, being about 8-12% harder to detect misspellings.  That is &lt;br /&gt;why books and newspapers use lowercase. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I only want the emp_id(s) where the action_code = 'VO' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and the previous action_code (by action_date) = 'AD' &lt;br /&gt;or the previous action_code (by action_date) = 'AD' with any &lt;br /&gt;action_code in between &lt;br /&gt;except 'AT'; &lt;&lt; &lt;br /&gt;&lt;br /&gt;SELECT DISTINCT emp_id &lt;br /&gt;  FROM PersonnelAction AS PVO, &lt;br /&gt;       PersonnelAction AS PAD &lt;br /&gt; WHERE PVO.emp_id = PAD.emp_id &lt;br /&gt;   AND PVO.action_code = 'VO' &lt;br /&gt;   AND PAD.action_code = 'AD' &lt;br /&gt;   AND PAD.action_date &lt; PVO.action_date &lt;br /&gt;   AND NOT EXISTS &lt;br /&gt;       (SELECT * &lt;br /&gt;          FROM PersonnelAction AS PAT &lt;br /&gt;         WHERE PAT.action_code = 'AT' &lt;br /&gt;           AND PAT.emp_id = PVO.emp_id &lt;br /&gt;           AND PAT_action_date BETWEEN PAD.action_date AND &lt;br /&gt;PVO.action_date);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438201035127210?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438201035127210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438201035127210' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438201035127210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438201035127210'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/complex-query.html' title='complex(?) query'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438178404791668</id><published>2006-11-24T10:20:00.000-05:00</published><updated>2006-11-24T10:23:04.176-05:00</updated><title type='text'>one to one random mapping between int</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I need to one-to-one map a range of integer (A), say 1 to 10000, randomly to &lt;br /&gt;1 to 10000 (B). And I need to get A if a B is given. Any existed good &lt;br /&gt;algorithm in T-SQL? &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Here is an implementation of the additive congruential method of&lt;br /&gt;generating values in pseudo-random order and is due to Roy Hann of&lt;br /&gt;Rational Commerce Limited, a CA-Ingres consulting firm. It is based on&lt;br /&gt;a shift-register and an XOR-gate, and it has its origins in&lt;br /&gt;cryptography. While there are other ways to do this, this code is nice&lt;br /&gt;because:&lt;br /&gt;&lt;br /&gt;1) The algorithm can be written in C or another low level language for&lt;br /&gt;speed. But math is fairly simple even in base ten.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) The algorithm tends to generate successive values that are (usually)&lt;br /&gt;"far apart", which is handy for improving the performance of tree&lt;br /&gt;indexes. You will tend to put data on separate physical data pages in&lt;br /&gt;storage.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) The algorithm does not cycle until it has generated every possible&lt;br /&gt;value, so we don't have to worry about duplicates. Just count how many&lt;br /&gt;calls have been made to the generator.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4) The algorithm produces uniformly distributed values, which is a nice&lt;br /&gt;mathematical property to have. It also does not include zero.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Generalizing the algorithm to arbitrary binary word sizes, and&lt;br /&gt;therefore longer number sequences, is not as easy as you might think.&lt;br /&gt;Finding the "tap" positions where bits are extracted for feedback&lt;br /&gt;varies according to the word-size in an extremely non-obvious way.&lt;br /&gt;Choosing incorrect tap positions results in an incomplete and usually&lt;br /&gt;very short cycle, which is unusable. If you want the details and tap&lt;br /&gt;positions for words of one to 100 bits, see E. J. Watson, "Primitive&lt;br /&gt;Polynomials (Mod 2)", Mathematics of Computation, v.16, 1962,&lt;br /&gt;p.368-369. Here is code for a 31-bit integer, which you can use:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;see the details at:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.rationalcommerce.com/resources/surrogates.htm"&gt;http://www.rationalcommerce.com/resources/surrogates.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;UPDATE generator31&lt;br /&gt;SET keyval&lt;br /&gt;= keyval/2 + MOD(MOD(keyval, 2) + MOD(keyval/2, 2), 2) * 8;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;T-SQL version:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Generator31 (keyval INTEGER NOT NULL);&lt;br /&gt;INSERT INTO Generator31 VALUES (1); -- any start value&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Generator31&lt;br /&gt;SET keyval =&lt;br /&gt;keyval/2 + ((keyval % 2) + (keyval/8 % 2) % 2)* 8&lt;br /&gt;SELECT * FROM Generator31;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Or if you prefer, the algorithm in C:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int Generator31 ()&lt;br /&gt;{static int n = 1;&lt;br /&gt;n = n &gt;&gt; 1  ((n^n &gt;&gt; 3) &amp; 1) &lt;&lt; 30;&lt;br /&gt;return n;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438178404791668?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438178404791668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438178404791668' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438178404791668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438178404791668'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/one-to-one-random-mapping-between-int.html' title='one to one random mapping between int'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438144715117951</id><published>2006-11-24T10:13:00.000-05:00</published><updated>2006-11-24T10:17:27.423-05:00</updated><title type='text'>oining on "between x and y"</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have these tables: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sales (SaleId, ProductId, QTY) &lt;br /&gt;Bandwidth (ProductId, RangeFrom, RangeTo, Price) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A RangeTo field is included in the Bandwidth table cause an "open end" &lt;br /&gt;is possible; 1-10, 11-20, 21&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now i would like to get a table like: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SalesView(SaleId, ProductId, Qty, Price) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Where price has to be NULL if it cannot be matched in the bandwith &lt;br /&gt;table; i always need all the records from the Sales table... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I tried something like this &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT s.SaleId, s.ProductId, s.QTY, s.QTY*b.Price AS Price &lt;br /&gt;FROM tblSales s &lt;br /&gt;INNER JOIN tblBandwidth b &lt;br /&gt;ON b.ProductId = s.ProductID &lt;br /&gt;AND &lt;br /&gt;( &lt;br /&gt;  s.QTY BETWEEN b.RangeFrom AND b.RangeTo &lt;br /&gt;OR &lt;br /&gt;  (s.QTY &gt;= b.RangeFrom AND b.RangeTo IS NULL) &lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With inner join i don't get all sales records (there out of range), &lt;br /&gt;with outer join i get them doubled or more (and i don't want to use a &lt;br /&gt;DISTINCT) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any great ideas? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; A RangeTo field [sic] is included in the Bandwidth table cause an "open end"  is possible; 1-10, 11-20, 21 &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That usually means that the price for that range holds for all &lt;br /&gt;quantities over the from range value.  In your example, any ordr over &lt;br /&gt;21 units gets that same unit price.  But then you say: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; price has to be NULL if it cannot be matched in the bandwith table; i always need all the records [sic] from the Sales table... &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can use DRI to force all sales to be of actual products you stock, &lt;br /&gt;and for every bandwidth to reference a real product.  You should not &lt;br /&gt;have any missing data if you design the schema properly.  Here is a &lt;br /&gt;guess at what you want: &lt;br /&gt;&lt;br /&gt;CREATE TABLE Sales &lt;br /&gt;(sale_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; product_id INTEGER NOT NULL &lt;br /&gt;    REFERENCES Products(product_id), &lt;br /&gt; sold_qty INTEGER NOT NULL &lt;br /&gt;  CHECK(sold_qty &gt; 0)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Bandwidth -- weird name, why not Discounts? &lt;br /&gt;(product_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Products(product_id), &lt;br /&gt; from_range INTEGER DEFAULT 1  NOT NULL &lt;br /&gt;  CHECK (from_range &gt; 0), &lt;br /&gt; to_range INTEGER, &lt;br /&gt;  CHECK(from_range &lt;= to_range), &lt;br /&gt; unit_price DECIMAL (10,4) NOT NULL, &lt;br /&gt; PRIMARY KEY (product_id, from_range) ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you have a single price for an item, then the DEFAULT values will &lt;br /&gt;give you a (1, NULL) row in the Bandwidth table.  Hide the work in a &lt;br /&gt;VIEW that will always be current: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW SalesRevenue(sale_id, product_id, sale_qty, sale_total) &lt;br /&gt;AS &lt;br /&gt;SELECT S.sale_id, S.product_id, S.sale_qty, &lt;br /&gt;       S.sale_qty*B.unit_price &lt;br /&gt;  FROM Sales AS S, Bandwidth AS B &lt;br /&gt; WHERE B.product_id = S.product_id &lt;br /&gt;   AND S.sale_qty BETWEEN &lt;br /&gt;       B.from_range AND COALESCE (B.to_range, S.sale_qty); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The COALESCE() will handle any quantity not explicitly in the Bandwidth &lt;br /&gt;table. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;guess i didn't explain myself in such a good way. I might also used &lt;br /&gt;some strange descriptions like bandwidth, probably cause english is not &lt;br /&gt;my native language. But, let's not blame it on that; in the situation i &lt;br /&gt;have now, referential integrity by the database is not possible, for as &lt;br /&gt;far as i know, mainly because of: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* the actual quantity for 1 line item (i will use this term instead of &lt;br /&gt;sale) is determined by a group of line items (if 1 is updated the whole &lt;br /&gt;lot can switch into another range) &lt;br /&gt;* the bandwidth/ranges/discounts may have a closed range: "1-10, 11-20, &lt;br /&gt;21-30" (dont ask me why, commercial reasons probably) &lt;br /&gt;* the line items are gathered over a period of time; at time of closing &lt;br /&gt;the period the definete prices/tariff should be set; the system should &lt;br /&gt;indicate where bandwidth/ranges do not fit the quantities &lt;br /&gt;* different 'pricelists' can be applied to a set of 'line items'/sales &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;this is the reason why i stated "Where price has to be NULL if it &lt;br /&gt;cannot be matched in the bandwith &lt;br /&gt;table; i always need all the records from the Sales table... ", but &lt;br /&gt;maybe i should have used the word tariff, because i don't mean the &lt;br /&gt;qty*tariff result here, just the tariff. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; * the actual quantity for 1 line item (i will use this term instead of sale) is determined by a group of line items (if 1 is updated the whole lot can switch into another range)&lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I would use a VIEW with a GROUP BY to build these groups. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; * the bandwidth/ranges/discounts may have a closed range: "1-10, 11-20, 21-30" (dont ask me why, commercial reasons probably) &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is still strange to me, but okay ... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; * the line items are gathered over a period of time; at time of closing the period the definite prices/tariff should be set; the system should indicate where bandwidth/ranges do not fit the quantities  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And having a VIEW would let you keep the correct totals &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; * different 'pricelists' can be applied to a set of 'line items'/sales &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I would put all the price lists into one table, with the ranges and &lt;br /&gt;price list name ("A list" customers, "B list" customers, etc.) &lt;br /&gt;&lt;br /&gt;Here is a slight re-write; see if it helps &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Sales &lt;br /&gt; (sale_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt;  product_id INTEGER NOT NULL &lt;br /&gt;    REFERENCES Products(product_id), &lt;br /&gt;  sold_qty INTEGER NOT NULL &lt;br /&gt;   CHECK(sold_qty &gt; 0)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; CREATE TABLE Bandwidth -- weird name, why not Discounts? &lt;br /&gt; (product_id INTEGER NOT NULL &lt;br /&gt;    REFERENCES Products(product_id), &lt;br /&gt; from_range INTEGER DEFAULT 1  NOT NULL &lt;br /&gt;   CHECK (from_range &gt; 0), &lt;br /&gt;  to_range INTEGER NOT NULL,  -- fix this constraint &lt;br /&gt;   CHECK(from_range &lt;= to_range), &lt;br /&gt;  unit_price DECIMAL (10,4) NOT NULL, &lt;br /&gt;  PRIMARY KEY (product_id, from_range) ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Use an OUTER JOIN to presrve the sales data. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; CREATE VIEW SalesRevenue(sale_id, product_id, sale_qty, sale_total) &lt;br /&gt; AS &lt;br /&gt; SELECT S.sale_id, S.product_id, S.sale_qty, &lt;br /&gt;        S.sale_qty*B.unit_price &lt;br /&gt;   FROM Sales AS S &lt;br /&gt;      LEFT OUTER JOIN &lt;br /&gt;      Bandwidth AS B &lt;br /&gt;     ON B.product_id = S.product_id &lt;br /&gt;    AND S.sale_qty BETWEEN &lt;br /&gt;        B.from_range AND B.to_range;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438144715117951?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438144715117951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438144715117951' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438144715117951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438144715117951'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/oining-on-between-x-and-y.html' title='oining on &quot;between x and y&quot;'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438123231097189</id><published>2006-11-24T10:12:00.000-05:00</published><updated>2006-11-24T10:13:52.536-05:00</updated><title type='text'>query question...</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;hi, not sure if db2 has a aggregate function to 'sum (concat)' a string &lt;br /&gt;column in a group by? &lt;br /&gt;i have a table like this: &lt;br /&gt;myCategory, mySubCategory, myGroup, mySubGroup, myString &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey1, 'string1' &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey2, 'string2' &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey2, 'string3' &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey1, 'string4' &lt;br /&gt;...... &lt;br /&gt;&lt;br /&gt;i want to group CatKye, SubCatKey, GrpKey, SubGrpKey &lt;br /&gt;so, the result set to be like this (in sorted order): &lt;br /&gt;myCategory, mySubCategory, myGroup, mySubGroup, myString &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey1, 'string1,string4' &lt;br /&gt;CatKey1, SubCatKey1, GrpKey1, SubGrpKey2, 'string2,string3' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;any idea? i heard there is something like ROWCONCAT... didn't find it &lt;br /&gt;in db2 reference though. &lt;br /&gt;thanks a lot. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;What you are looking for exists in Sybase as LIST() and one of the open &lt;br /&gt;source products (Posttgres?  I cannot remember).   But that is not the &lt;br /&gt;real question.  Why do you wish to destroy First Normal Form (1NF) with &lt;br /&gt;a concatendated list structure?  It is the foundation of RDBMS, after &lt;br /&gt;all. &lt;br /&gt;&lt;br /&gt;Why are you formatting data in the back end?  The basic principle of a &lt;br /&gt;tiered architecture is that display is done in the front end and never &lt;br /&gt;in the back end.  This a more basic programming principle than just SQL &lt;br /&gt;and RDBMS. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Yes, there are kludges in SQL to do this.  You can also still write &lt;br /&gt;procedural code with GOTOs and get "spaghetti code", but it does not &lt;br /&gt;mean you should.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438123231097189?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438123231097189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438123231097189' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438123231097189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438123231097189'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/query-question.html' title='query question...'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116438105802640879</id><published>2006-11-24T10:09:00.000-05:00</published><updated>2006-11-24T10:11:01.220-05:00</updated><title type='text'>dynamic cursor - sorting in declaration</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a small table "ABC" like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    id_position |   value &lt;br /&gt;--------------------------- &lt;br /&gt;        1            |    11 &lt;br /&gt;        2            |    22 &lt;br /&gt;        3            |    33 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I try to use a dynamic cursor as below. &lt;br /&gt;When the statement "order by id_position" in declare part of the cursor_abc &lt;br /&gt;is omitted - cursor work as it should. &lt;br /&gt;But when the statement "order by id_position" is used, cursor behave as &lt;br /&gt;static one. &lt;br /&gt;What's the matter, does anybody know? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Code: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;declare @id_position  as int, @value as int &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DECLARE cursor_abc CURSOR &lt;br /&gt;FOR &lt;br /&gt;select id_position, value from abc &lt;br /&gt;order by id_position &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;set nocount on &lt;br /&gt;open cursor_abc &lt;br /&gt;FETCH NEXT FROM cursor_abc &lt;br /&gt;INTO @id_position, @value &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;WHILE @@FETCH_STATUS = 0 &lt;br /&gt;BEGIN &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  print @id_position &lt;br /&gt;  print @value &lt;br /&gt;  print '----------------------------' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  update abc set value=666 --next reading should give value=666 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FETCH NEXT FROM cursor_abc &lt;br /&gt;   INTO @id_position, @value &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;END &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CLOSE cursor_abc &lt;br /&gt;DEALLOCATE cursor_abc &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;In many years of writing SQL, I have seldom found a need for a cursor. &lt;br /&gt;They usually run 1-2 orders of magnitude slower than a relational &lt;br /&gt;solution. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When someone uses one, it is generally becasue they are mimicing a &lt;br /&gt;magnetic tape file system, and probably violating the basic principle &lt;br /&gt;of a tiered architecture that display is done in the front end and &lt;br /&gt;never in the back end.  This a more basic programming principle than &lt;br /&gt;just SQL and RDBMS. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Finally, id_position is not an ISO-11179 data element name and it makes &lt;br /&gt;no sense.  Identifier of what? Position of what?  You have two &lt;br /&gt;adjectives without a noun.  But I bet you mant it to be PHYSICAL &lt;br /&gt;location because you are mimicing a magnetic tape file system, instead &lt;br /&gt;of using SQL for an RDBMS. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What is your real problem?  Show us and perhaps we can help you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116438105802640879?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116438105802640879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116438105802640879' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438105802640879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116438105802640879'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/dynamic-cursor-sorting-in-declaration.html' title='dynamic cursor - sorting in declaration'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116370143744730987</id><published>2006-11-16T13:23:00.000-05:00</published><updated>2006-11-16T13:23:57.980-05:00</updated><title type='text'>Totals Help</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Based on this query..... how can I total just the starred SYS_OP's produced &lt;br /&gt;column Compute by will sum them all. &lt;br /&gt;I want daily totals of just the starred operations but still list them all. &lt;br /&gt;&lt;br /&gt;DECLARE @sDate SmallDateTime &lt;br /&gt;DECLARE @sEnd  SmallDateTime &lt;br /&gt;DECLARE @sPart Char(15) &lt;br /&gt;SET @sDate = '20061002' &lt;br /&gt;SET @sEnd = '20061005' &lt;br /&gt;set @sPart = '24277' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET NOCOUNT ON &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT CONVERT(CHAR(10),C_DATE,101) as JT_DATE, &lt;br /&gt;JT.DEPT, JT.PART, OP AS JT_OP, &lt;br /&gt;CASE &lt;br /&gt;  WHEN LOD.LAST_OP IS NULL  THEN '' &lt;br /&gt;ELSE &lt;br /&gt;  '***' &lt;br /&gt;END &lt;br /&gt;AS SYS_OP, &lt;br /&gt;SHIFT, C_COUNT AS PRODUCED &lt;br /&gt;FROM Label_Audit..JOB_TICKETS_RAW JT &lt;br /&gt;LEFT JOIN LABEL_AUDIT..V_LAST_OP_DEPT LOD &lt;br /&gt;ON LOD.PART = JT.PART &lt;br /&gt;AND JT.OP = LOD.LAST_OP &lt;br /&gt;WHERE C_DATE BETWEEN @sDate AND @sEnd &lt;br /&gt;AND JT.PART = @sPart &lt;br /&gt;ORDER BY C_DATE, OP, SHIFT &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;JT_DATE    DEPT PART       OP    SYS_OP SHIFT PRODUCED &lt;br /&gt;---------- ---- --------------- ----- ------ ----- ----------- &lt;br /&gt;10/02/2006 8800 24277           020          1     134 &lt;br /&gt;10/03/2006 8800 24277           020          1     201 &lt;br /&gt;10/03/2006 8800 24277           020          2     405 &lt;br /&gt;10/03/2006 8800 24277           020          3     500 &lt;br /&gt;10/04/2006 8800 24277           020          1     625 &lt;br /&gt;10/04/2006 8800 24277           020          2     620 &lt;br /&gt;10/04/2006 8800 24277           020          3     100 &lt;br /&gt;10/04/2006 8800 24277           025          2     634 &lt;br /&gt;10/04/2006 8800 24277           025          3     950 &lt;br /&gt;10/04/2006 8800 24277           030   ***    1     891 &lt;br /&gt;10/04/2006 8800 24277           030   ***    2     634 &lt;br /&gt;10/04/2006 8800 24277           030   ***    3     950 &lt;br /&gt;10/04/2006 8800 24277           030A         1     891 &lt;br /&gt;10/05/2006 8800 24277           020          3     401 &lt;br /&gt;10/05/2006 8800 24277           025          3     821 &lt;br /&gt;10/05/2006 8800 24277           030   ***    3     821 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;1) start using ISO-8601 formats for dates, not local dialect &lt;br /&gt;&lt;br /&gt;2) start using valid data element names (part?? Unh?! part_name? &lt;br /&gt;part_nbr? part_wgt?) Is c_date "completion_date?" or what?  Write code &lt;br /&gt;as if another human being has to maintain it after you win the lottery. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Real SQL programmers do not write proprietary, deprecated COMPUTE BY &lt;br /&gt;clause.  This is a decades old legacy kludge from the Sybase days when &lt;br /&gt;there were no report writers.  Welcome to the year 2006 (actually, this &lt;br /&gt;was bad code in 1996).  You ought to be doing this in a proper tool and &lt;br /&gt;not trying to fake a 1950's break and total file system report. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4) Your spec does not tell us what to sum!  Production, maybe?  And &lt;br /&gt;what do we group by?  Here is a skeleton query: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT .. &lt;br /&gt; SUM (CASE  WHEN LOD.last_op IS NULL THEN  c_count  ELSE 0 END) AS &lt;br /&gt;star_stuff &lt;br /&gt; SUM (CASE  WHEN LOD.last_op IS NOT NULL THEN  c_count  ELSE 0 END) AS &lt;br /&gt;other_stuff &lt;br /&gt;FROM .. &lt;br /&gt;WHERE .. &lt;br /&gt;GROUP BY .. ;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116370143744730987?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116370143744730987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116370143744730987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116370143744730987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116370143744730987'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/totals-help.html' title='Totals Help'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116369249320205503</id><published>2006-11-16T10:52:00.000-05:00</published><updated>2006-11-16T10:55:44.613-05:00</updated><title type='text'>sql statement</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;What is wrong int this SQL statement? &lt;br /&gt;&lt;br /&gt;select top 10 DOCInt.*, DOCDet.* , Cate.*, Arti.*, [Ar An].* &lt;br /&gt;from &lt;br /&gt;DOCInt INNER JOIN DOCDet ON DOCInt.CodDoc=DOCDet.CodDoc &lt;br /&gt;LEFT JOIN Cate ON DOCDet.IDCategory=Cate.[ID Category] &lt;br /&gt;LEFT JOIN Arti ON DOCDet.IDArti=Arti.[ID Arti] &lt;br /&gt;INNER JOIN [Ar An] ON DOCInt.IDAnag=[Ar An].[ID An] &lt;br /&gt;GROUP BY DOCInt.IDDoc &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; What is wrong in this SQL statement? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Well, your names are a nightmare that violate common sense and &lt;br /&gt;ISO-11179 rules, but for now, you do not understand how a SELECT (GROUP &lt;br /&gt;BY in particular) work: &lt;br /&gt;&lt;br /&gt;Here is how a SELECT works in SQL ... at least in theory.  Real &lt;br /&gt;products will optimize things, but the code has to produce the same &lt;br /&gt;results. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; a) Start in the FROM clause and build a working table from all of the &lt;br /&gt;joins, unions, intersections, and whatever other table constructors are &lt;br /&gt;there.  The [table expression] AS [correlation name] option allows you &lt;br /&gt;give a name to this working table which you then have to use for the &lt;br /&gt;rest of the containing query. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; b) Go to the WHERE clause and remove rows that do not pass criteria; &lt;br /&gt;that is, that do not test to TRUE (i.e. reject UNKNOWN and FALSE).  The &lt;br /&gt;WHERE clause is applied to the working set in the FROM clause. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; c) Go to the optional GROUP BY clause, partiton the original table &lt;br /&gt;into groups and reduce each grouping to a *single* row, replacing the &lt;br /&gt;original working table with the new grouped table. The rows of a &lt;br /&gt;grouped table must be only group characteristics: (1) a grouping column &lt;br /&gt;(2) a statistic about the group (i.e. aggregate functions) (3) a &lt;br /&gt;function or constant(4) an expression made up of only those three &lt;br /&gt;items.  The original table no longer exists and you cannot reference &lt;br /&gt;anything in it (this was an error in early Sybase products). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; d) Go to the optional HAVING clause and apply it against the grouped &lt;br /&gt;working table; if there was no GROUP BY clause, treat the entire table &lt;br /&gt;as one group. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; e) Go to the SELECT clause and construct the expressions in the list. &lt;br /&gt;This means that the scalar subqueries, function calls and expressions &lt;br /&gt;in the SELECT are done after all the other clauses are done.  The AS &lt;br /&gt;operator can also give names to expressions in the SELECT list.  These &lt;br /&gt;new names come into existence all at once, but after the WHERE clause, &lt;br /&gt;GROUP BY clause and HAVING clause have been executed; you cannot use &lt;br /&gt;them in the SELECT list or the WHERE clause for that reason. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If there is a SELECT DISTINCT, then redundant duplicate rows are &lt;br /&gt;removed.  For purposes of defining a duplicate row, NULLs are treated &lt;br /&gt;as matching (just like in the GROUP BY). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; f) Nested query expressions follow the usual scoping rules you would &lt;br /&gt;expect from a block structured language like C, Pascal, Algol, etc. &lt;br /&gt;Namely, the innermost queries can reference columns and tables in the &lt;br /&gt;queries in which they are contained. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; g) The ORDER BY clause is part of a cursor, not a query. The result &lt;br /&gt;set is passed to the cursor, which can only see the names in the SELECT &lt;br /&gt;clause list, and the sorting is done there.  The ORDER BY clause cannot &lt;br /&gt;have expression in it, or references to other columns because the &lt;br /&gt;result set has been converted into a sequential file structure and that &lt;br /&gt;is what is being sorted. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see, things happen "all at once" in SQL, not "from left to &lt;br /&gt;right" as they would in a sequential file/procedural language model. In &lt;br /&gt;those languages, these two statements produce different results: &lt;br /&gt;  READ (a, b, c) FROM File_X; &lt;br /&gt;  READ (c, a, b) FROM File_X; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;while these two statements return the same data: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT a, b, c FROM Table_X; &lt;br /&gt;SELECT c, a, b FROM Table_X; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Think about what a confused mess this statement is in the SQL model. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT f(c2) AS c1, f(c1) AS c2 FROM Foobar; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is why such nonsense is illegal syntax.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116369249320205503?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116369249320205503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116369249320205503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369249320205503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369249320205503'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/sql-statement.html' title='sql statement'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116369235176453268</id><published>2006-11-16T10:50:00.000-05:00</published><updated>2006-11-16T10:52:32.006-05:00</updated><title type='text'>Help me convince them this is bad!!!</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have an IT manager that thinks he knows everything when it comes to&lt;br /&gt;database design. Unfortunately, he's not familiar with relational&lt;br /&gt;databases but thinks he knows it all. He's come up with a really crazy&lt;br /&gt;design, and I've got to come up with all the reasons it's not right. I&lt;br /&gt;want to have as much ammo as possible so we're not stuck supporting&lt;br /&gt;something that will never perform well.&lt;br /&gt;&lt;br /&gt;We're in the process of moving some functionality from a Z/OS DB2&lt;br /&gt;database to a RS/6000 DB2. Currently the Z/OS database has a table&lt;br /&gt;that has a four column primary key. We've determined that one of these&lt;br /&gt;keys is not needed on the new system, which would leave us with a three&lt;br /&gt;column key. However, the manager wants to make it a two column key, be&lt;br /&gt;concatenating two of the source columns (separated by double commas)&lt;br /&gt;into just one column on the new system. Searches can be done on either&lt;br /&gt;of the source columns or both.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I know searching this will be horrific, with tons of LIKE statements,&lt;br /&gt;and indexing will be next to useless. But I need as many reasons as&lt;br /&gt;possible to not take this approach. I don't want to end up being&lt;br /&gt;blamed for poor performance down the road.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; He wants to make this a generic table, that can be used for different types of data in the future. &lt;&lt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Pretty clearly the concatenated column is a total violation of 1NF.&lt;br /&gt;Likewise, a "generic table" a violation of logic and RDBMS. I call&lt;br /&gt;such things "Britney Spears, Automobiles and Squid" tables to show that&lt;br /&gt;they cannot even have a basic ISO-11179 data element name. "To be is&lt;br /&gt;to be something in particular; to be nothing in particular is to be&lt;br /&gt;nothing at all" -- Aristotle&lt;br /&gt;&lt;br /&gt;Here is a little "cut *&amp; paste" I give people who want ot do a EAV&lt;br /&gt;design. Someone like your boss posted this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE EAV -- no key declared&lt;br /&gt;(key_col VARCHAR (10) NULL,&lt;br /&gt;attrib_value VARCHAR (50) NULL);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO EAV VALUES ('LOCATION','Bedroom');&lt;br /&gt;INSERT INTO EAV VALUES ('LOCATION','Dining Room');&lt;br /&gt;INSERT INTO EAV VALUES ('LOCATION','Bathroom');&lt;br /&gt;INSERT INTO EAV VALUES ('LOCATION','courtyard');&lt;br /&gt;INSERT INTO EAV VALUES ('EVENT','verbal aggression');&lt;br /&gt;INSERT INTO EAV VALUES ('EVENT','peer');&lt;br /&gt;INSERT INTO EAV VALUES ('EVENT','bad behavior');&lt;br /&gt;INSERT INTO EAV VALUES ('EVENT','other');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE EAV_DATA -note lack of constraints, defaults, DRI&lt;br /&gt;(id INTEGER IDENTITY (1,1) NOT NULL,&lt;br /&gt;bts_id INTEGER NULL,&lt;br /&gt;key_col VARCHAR (10) NULL,&lt;br /&gt;attrib_value VARCHAR (50) NULL );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO EAV_DATA VALUES (1, 'LOCATION', 'Bedroom');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (1, 'EVENT', 'other');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (1, 'EVENT', 'bad behavior');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (2, 'LOCATION', 'Bedroom');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (2, 'EVENT', 'other');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (2, 'EVENT', 'verbal aggression');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (3, 'LOCATION', 'courtyard');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (3, 'EVENT', 'other');&lt;br /&gt;INSERT INTO EAV_DATA VALUES (3, 'EVENT', 'peer');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ideally, the result set of the query would be Location Event count&lt;br /&gt;(headings if possible)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bedroom verbal aggression 1&lt;br /&gt;Bedroom peer 0&lt;br /&gt;Bedroom bad behavior 0&lt;br /&gt;Bedroom other 2&lt;br /&gt;Dining Room verbal aggression 0&lt;br /&gt;Dining Room peer 0&lt;br /&gt;Dining Room bad behavior 0&lt;br /&gt;Dining Room other 0&lt;br /&gt;Bathroom verbal aggression 0&lt;br /&gt;Bathroom peer 0&lt;br /&gt;Bathroom bad behavior 0&lt;br /&gt;Bathroom other 0&lt;br /&gt;courtyard verbal aggression 0&lt;br /&gt;courtyard peer 1&lt;br /&gt;courtyard bad behavior 0&lt;br /&gt;courtyard other 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also, if possible, another query would return this result set. (I think&lt;br /&gt;I know how to do this one.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Location Event count&lt;br /&gt;Bedroom verbal aggression 1&lt;br /&gt;Bedroom other 2&lt;br /&gt;courtyard peer 1&lt;br /&gt;courtyard other 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is an answer From: Thomas Coleman&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT Locations.locationvalue, Events.eventvalue,&lt;br /&gt;(SELECT COUNT(*)&lt;br /&gt;FROM (SELECT LocationData.locationvalue, EventData.eventvalue&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FROM (SELECT TD1.bts_id, TD1.value AS locationvalue&lt;br /&gt;FROM eav_data AS TD1&lt;br /&gt;WHERE TD1.key = 'location') AS LocationData&lt;br /&gt;INNER JOIN&lt;br /&gt;(SELECT TD2.bts_id, TD2.value AS eventvalue&lt;br /&gt;FROM eav_data AS TD2&lt;br /&gt;WHERE TD2.key = 'event'&lt;br /&gt;) AS EventData&lt;br /&gt;ON LocationData.bts_id = EventData.bts_id&lt;br /&gt;) AS CollatedEventData&lt;br /&gt;WHERE CollatedEventData.locationvalue = Locations.locationvalue&lt;br /&gt;AND CollatedEventData.eventvalue = Events.eventvalue&lt;br /&gt;FROM (SELECT T1.value AS locationvalue&lt;br /&gt;FROM EAV AS T1&lt;br /&gt;WHERE T1.key = 'location') AS Locations,&lt;br /&gt;(SELECT T2.value AS eventvalue&lt;br /&gt;FROM EAV AS T2&lt;br /&gt;WHERE T2.key = 'event') AS Events&lt;br /&gt;ORDER BY Locations.locationvalue, Events.eventvalue ,&lt;br /&gt;SELECT Locations.locationvalue, Events.eventvalue&lt;br /&gt;(SELECT COUNT(*)&lt;br /&gt;FROM (SELECT LocationData.locationvalue, EventData.eventvalue&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FROM (SELECT TD1.bts_id, TD1.value AS locationvalue&lt;br /&gt;FROM eav_data AS TD1&lt;br /&gt;WHERE TD1.key = 'location') AS LocationData&lt;br /&gt;INNER JOIN&lt;br /&gt;(SELECT TD2.bts_id, TD2.value AS eventvalue&lt;br /&gt;FROM eav_data AS TD2&lt;br /&gt;WHERE TD2.key = 'event') AS EventData&lt;br /&gt;ON LocationData.bts_id = EventData.bts_id)&lt;br /&gt;AS CollatedEventData&lt;br /&gt;WHERE CollatedEventData.locationvalue = Locations.locationvalue&lt;br /&gt;AND CollatedEventData.eventvalue = Events.eventvalue)&lt;br /&gt;FROM (SELECT T1.value AS locationvalue&lt;br /&gt;FROM EAV AS T1&lt;br /&gt;WHERE T1.key = 'location') AS Locations,&lt;br /&gt;(SELECT T2.value AS eventvalue&lt;br /&gt;FROM EAV AS T2&lt;br /&gt;WHERE T2.key = 'event') AS Events;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is the same thing in a proper schema as:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT L.locationvalue, E.eventvalue, COUNT(*)&lt;br /&gt;FROM Locations AS L, Events AS E&lt;br /&gt;WHERE L.btd_id = E.btd_id&lt;br /&gt;GROUP BY L.locationvalue, E.eventvalue;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reason that I had to use so many subqueries is that those entities&lt;br /&gt;are all plopped into the same table. There should be separate tables&lt;br /&gt;for Locations and Events.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The column names are seriously painful Don't use "key" and "value" for&lt;br /&gt;column names. It means that the developer *has* surround the column&lt;br /&gt;name with double quotes for everything which is a serious pain.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There is such a thing as "too" generic. There has to be some structure&lt;br /&gt;or everything becomes nothing more than a couple of tables called&lt;br /&gt;"things". The real key (no pun intended) is commonality. Is there a&lt;br /&gt;pattern to the data that they want to store? It may not be possible to&lt;br /&gt;create one structure to rule them all and in the darkness bind them.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"To be is to be something in particular; to be nothing in particular is&lt;br /&gt;to be nothing." --Aristole&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;All data integrity is destroyed. Any typo becomes a new attribute or&lt;br /&gt;entity. Entities are found missing attributes, so all the reports are&lt;br /&gt;wrong.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Try to write a single CHECK() constraint that works for all the&lt;br /&gt;attributes of those 30+ entities your users created because you were&lt;br /&gt;too dumb or too lazy to do your job. It can be done! You need a case&lt;br /&gt;expression almost 70 WHEN clauses for a simple invoice and order system&lt;br /&gt;when I tried it as an exercise.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Try to write a single DEFAULT clause for 30+ entities crammed into one&lt;br /&gt;column. Impossible!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Try to set up DRI actions among the entities. If you thought the WHEN&lt;br /&gt;clauses in the single CASE expression were unmaintainable, wait until&lt;br /&gt;you see the "TRIGGERs from Hell" -- Too bad that they might not fit&lt;br /&gt;into older SQL Server which had some size limits. Now maintain it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116369235176453268?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116369235176453268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116369235176453268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369235176453268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369235176453268'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/help-me-convince-them-this-is-bad.html' title='Help me convince them this is bad!!!'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116369215331580068</id><published>2006-11-16T10:48:00.000-05:00</published><updated>2006-11-16T10:49:13.786-05:00</updated><title type='text'>Best way to force a varchar column to have no whitespace</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a column that I do not want any whitespace in whatsoever. I'm &lt;br /&gt;wondering how do enforce this a DDL level instead of in 40 million &lt;br /&gt;seat-of-the-pants after-the-fact computer programs accessing the &lt;br /&gt;database. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;CONSTRAINT no_white_space &lt;br /&gt;    CHECK ( LEW(foo)  = LEN (REPLACE (foo, ' ', ''))) &lt;br /&gt;&lt;br /&gt;You can then nest calls to REPLACE() for tabs,newlines, etc. easily.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116369215331580068?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116369215331580068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116369215331580068' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369215331580068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116369215331580068'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/11/best-way-to-force-varchar-column-to.html' title='Best way to force a varchar column to have no whitespace'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116222416589111621</id><published>2006-10-30T11:01:00.000-05:00</published><updated>2006-10-30T11:02:46.036-05:00</updated><title type='text'>Algorithm Question</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have user table named TBL_USER which has userid and username fields. &lt;br /&gt;&lt;br /&gt;I have another table named TBL_PRODUCT  which need user info in it &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Which way you offer me to follow . &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. Having  Userid Field in TBL_Product &lt;br /&gt;or &lt;br /&gt;2. Having Username field in TBL_PRODUCT &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;to have relationship between 2 tables. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Could you explain which way i should follow and wht i should follow ? &lt;br /&gt;You might give a web url .. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;First, stop using uppercase names that violate ISO-11179 rules.  Those &lt;br /&gt;prefixes are redundant, mess up the data dictionary. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have user table named TBL_USER which has userid and username field [sic] &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Columns are not fields.  The source of your design problem is that you &lt;br /&gt;do not know what a table, coluymn or row are.  Let's try guess at the &lt;br /&gt;proper DDL, since you did not bother to post anything: &lt;br /&gt;&lt;br /&gt;CREATE TABLE Users &lt;br /&gt;(user_id INTEGER NOT NULL PRIMARY KEY &lt;br /&gt;   CHECK (&lt;&lt;validation rule&gt;&gt;, &lt;br /&gt; user_name VARCHAR(35) NOT NULL, &lt;br /&gt; etc); &lt;br /&gt;. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have another table named TBL_PRODUCT  which need user info in it &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NO!  Why is a user attribute part of a set of products?? &lt;br /&gt;&lt;br /&gt;CREATE TABLE Products &lt;br /&gt;(product_id INTEGER NOT NULL PRIMARY KEY &lt;br /&gt;   CHECK (&lt;&lt;validation rule&gt;&gt;, &lt;br /&gt; product_name VARCHAR(35) NOT NULL, &lt;br /&gt;  etc.); &lt;br /&gt;. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Which way you offer me to follow ..  to have relationship between 2 tables. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Of course. &lt;br /&gt;&lt;br /&gt;CREATE TABLE Purchases &lt;br /&gt;(product_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Products(product_id) &lt;br /&gt;   ON UPDATE CASCADE &lt;br /&gt;   ON  DELETE CASCADE,  -- guess at the rules &lt;br /&gt; user_id INTEGER NOT NULL &lt;br /&gt;   REFERENCES Users(user_id) &lt;br /&gt;   ON UPDATE CASCADE &lt;br /&gt;   ON  DELETE CASCADE,   -- guess at the rules &lt;br /&gt; PRIMARY KEY (user_id, product_id), &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Could you explain which way I should follow and why i.. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any book on basic data modeling will tell you.  A table is not a file; &lt;br /&gt;it represents a set of entities of the same kind and their attributes &lt;br /&gt;or it models a relationship -- never both in one table.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116222416589111621?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116222416589111621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116222416589111621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116222416589111621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116222416589111621'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/algorithm-question.html' title='Algorithm Question'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116222374618878257</id><published>2006-10-30T10:55:00.000-05:00</published><updated>2006-10-30T10:56:05.326-05:00</updated><title type='text'>SQL search returning duplicate values</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am having some trouble.  I am doing some db search tests before &lt;br /&gt;moving from access to mysql/sql server.  Before I get into the Full &lt;br /&gt;Text Search battle..... &lt;br /&gt;&lt;br /&gt;If I try to do the following and there are multiple stores who have the &lt;br /&gt;same book, all values are returned, which make duplicate entries in the &lt;br /&gt;results.  How do I accomplish the following but get a single price &lt;br /&gt;value?  How do I get the lowest, highest, middle, n'th etc value? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT DISTINCT tblBook.*,  tblStore.Price &lt;br /&gt;FROM tblBook INNER JOIN tblStore ON tblBook.ID = tblStore.BookID &lt;br /&gt;WHERE (((tblBook.Description) Like '%value%')); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tblBook             tblStore &lt;br /&gt;========            ======== &lt;br /&gt;ID------------|     ID &lt;br /&gt;Value        |------BookID &lt;br /&gt;Description         Price &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Any help would be greatly appreciated. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why did you make the book price an attribute of a store instead of the &lt;br /&gt;book???  Think about it. &lt;br /&gt;&lt;br /&gt;Also, read something about ISO-11179 metadata rules, so you will stop &lt;br /&gt;using things like "tblBook"  (a scalar value because it is singular and &lt;br /&gt;it belongs to a piece of furniture  -- I would have modeled a set of &lt;br /&gt;book titles in my schema).  Why does the book_id attribute change names &lt;br /&gt;from table to table?  Did you know that the ISBN-13 is the standard &lt;br /&gt;identifier for books? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the real world, you would have several prices for a book (wholesale, &lt;br /&gt;retail, discounted, etc.) and they would be with the book.  The min and &lt;br /&gt;max prices would be known and then you can use a weighted average to &lt;br /&gt;get a "middle" value.  That means you need a quantity at each price &lt;br /&gt;point. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your current design is too simple for your query.  Perhaps you use a &lt;br /&gt;discount scale based on volume, or classes like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE BookSales -- plural name for a set!! no redundant prefixes &lt;br /&gt;(isbn CHAR(13) NOT NULL PRIMARY KEY, -- industry standards &lt;br /&gt; wholesale_price DECIMAL (8,4) NOT NULL, &lt;br /&gt; wholesale_qty INTEGER DEFAULT 0 NOT NULL, &lt;br /&gt; retail_price DECIMAL (8,4) NOT NULL, &lt;br /&gt; retail_qty INTEGER DEFAULT 0 NOT NULL, &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Start over and get some help from someone who knows how to do the model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116222374618878257?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116222374618878257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116222374618878257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116222374618878257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116222374618878257'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/sql-search-returning-duplicate-values.html' title='SQL search returning duplicate values'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116118067755671367</id><published>2006-10-18T09:57:00.000-04:00</published><updated>2006-10-18T10:11:20.810-04:00</updated><title type='text'>Default IN</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I want to pass parameters to a sql query. For example: &lt;br /&gt;&lt;br /&gt;WHERE ANS IN (" &amp; MyString &amp; ") &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So if MyString = 'This', 'That', 'The Other' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It will populate the Where clause. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But I also want to be able to pass an empty string and have it return &lt;br /&gt;all values for ANS. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any ideas? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I want to pass parameters to a sql query. For example: &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This comes up all the time from Newbies who do not work with a compiled &lt;br /&gt;language and have no idea what a parameter is.  You will get a FAQ to &lt;br /&gt;the standard kludges for this -- parsing routines without safety &lt;br /&gt;checks, dynamic SQL that can crash, etc. &lt;br /&gt;&lt;br /&gt;One answer is that T-SQL can handle up to 1024 parameters (REAL &lt;br /&gt;parameters, not things parsed off a single string in procedural code) &lt;br /&gt;and you will not need more than 100 in the real world.  Suddenly, you &lt;br /&gt;have all the power of the compiler to check data, to optimize, etc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Another answer is to load a working table with a single column.  The &lt;br /&gt;bad news is that in the year 2006, SQL is missing basic parts of the &lt;br /&gt;VALUES() clause that would make this very, very easy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116118067755671367?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116118067755671367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116118067755671367' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116118067755671367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116118067755671367'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/default-in.html' title='Default IN'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116117919510828340</id><published>2006-10-18T09:45:00.000-04:00</published><updated>2006-10-18T09:46:35.233-04:00</updated><title type='text'>Using one stored procedure to update table created in another?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a stored procedures which creates a new table and then runs a &lt;br /&gt;specific query.  The results of said query are then inserted into the &lt;br /&gt;newly created table.  Now, I have another stored procedure which &lt;br /&gt;should, in theory, update that new table with extra data. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I thought I could just do an update in the second sp but I'm hitting &lt;br /&gt;some problems.  Mainly, it's telling me that there's an invalid column &lt;br /&gt;name, error 207, although I copied and pasted the name so the spelling &lt;br /&gt;should match.  It tells me that "observation_report_id" is the invalid &lt;br /&gt;column name. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If it;s not the spelling of the name that's wrong, then what else could &lt;br /&gt;be it be?  Is there something else I'm missing that could bring up the &lt;br /&gt;207 error? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If I can't get this working, could I do it with parameters?  How would &lt;br /&gt;I go about passing the unique key for each row from sp1 to sp2? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks for any help, &lt;br /&gt;-M- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Code example: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE frm_CNE_BasicInfo_pt2 &lt;br /&gt;AS &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** run query and insert results **/ &lt;br /&gt;update tbl_CNE_BasicInfo &lt;br /&gt;set mainname=[mainname], &lt;br /&gt;heading=[heading], &lt;br /&gt;title=[title], &lt;br /&gt;where  obsRepID=observation_report_id &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Select obstable.n_number, obstable.taskname as taskname, &lt;br /&gt;obstable.observation_report_id, obstable.stream_id, mainname.mainname, &lt;br /&gt;heading.heading, title.title &lt;br /&gt;from (select p.n_number, tt.name as taskname, &lt;br /&gt;orr.observation_report_id, pp.stream_id &lt;br /&gt;from &lt;br /&gt;parent p, parentpast pp, pastor pr, observationreport orr, trequest tr, &lt;br /&gt;ttype tt &lt;br /&gt;where p.parent_id = pp.parent_id &lt;br /&gt;and pp.pastor_id = pr.pastor_id &lt;br /&gt;and p.record_status = 'A' &lt;br /&gt;and p.parent_id = orr.parent_id &lt;br /&gt;and p.parent_id = tr.parent_id &lt;br /&gt;and orr.trequest_id = tr.trequest_id &lt;br /&gt;and tr.ttype_id = tt.ttype_id &lt;br /&gt;and pp.stream_id = tr.stream_id &lt;br /&gt;)as obstable &lt;br /&gt;left outer join &lt;br /&gt;(select ao.observation_report_id, dt.name, ao.value  as mainname &lt;br /&gt;from &lt;br /&gt;atomicobservation ao &lt;br /&gt;inner join dtype dt &lt;br /&gt;on dt.dtype_id=ao.dtype_id &lt;br /&gt;where dt.name = 'mainname') &lt;br /&gt;as mainname &lt;br /&gt;on mainname.observation_report_id=obstable.observation_report_id &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;etc etc &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have a stored procedure which creates a new table and then runs a specific query.  The results of said query are then inserted into the newly created table.  Now, I have another stored procedure which should, in theory, update that new table with extra data. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is not how to write an RDBMS.  The schema is supposed to be a data &lt;br /&gt;model of some real world situation.  Creating tables on the fly is like &lt;br /&gt;elephants appearing out of the sky. &lt;br /&gt;&lt;br /&gt;What you seem to be doing is mimicking a file system.  Hang a scratch &lt;br /&gt;tape, dump some data to it.  In the next *procedural* step, update the &lt;br /&gt;scratch tape.  In declarative programming, we try to get the desired &lt;br /&gt;results in one step. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Given column names like "heading" and "title", it looks like you are &lt;br /&gt;formatting a report on the database instead of in your application. &lt;br /&gt;File systems and 3GL programming languages blend data and application &lt;br /&gt;code into the same module, but RDBMS is supposed to be a tiered &lt;br /&gt;architecture. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can probably kludge your way thru this, but I would re-think how &lt;br /&gt;you code in SQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116117919510828340?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116117919510828340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116117919510828340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116117919510828340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116117919510828340'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/using-one-stored-procedure-to-update.html' title='Using one stored procedure to update table created in another?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116117891640197504</id><published>2006-10-18T09:40:00.000-04:00</published><updated>2006-10-18T09:42:03.240-04:00</updated><title type='text'>Multiple bit data type in a table</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;We are going to have a table that store about 300 bit fields (answers to &lt;br /&gt;about 300 yes/no question for a client).  I am curious as to whether I need &lt;br /&gt;to split them based on the size of each row.  How are mulitiple bit fields &lt;br /&gt;in a table stored in SQL server 2000?  Also if each field allows null (or &lt;br /&gt;does not allow), how would that change the size of each row? &lt;br /&gt;&lt;br /&gt;Any insight, recommendation, advice would be appreciated. &lt;br /&gt;Thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; a table that store about 300 bit fields [sic] (answers to  about 300 yes/no question for a client). &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Bits are a low-level assembly language things that are a bitch to do &lt;br /&gt;anything high-level  with -- liker stat analysis.  Columns are nothing &lt;br /&gt;like fields.  You are still thinking in assembly language, not SQL. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Any insight, recommendation, advice would be appreciated. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Do not design questionaires this way.  First of all, there are very few &lt;br /&gt;independent yes/no questions.  You are looking for dependencies in the &lt;br /&gt;data; that is the whole point of gathering data. &lt;br /&gt;&lt;br /&gt;There are unanswered questions -- people do that!  There are &lt;br /&gt;interdependent questions -- "Are you female? No. Have you had cancer of &lt;br /&gt;the uterus? Yes" is clearly wrong and needs a N/A answer.  This means a &lt;br /&gt;decision table for the validation rules (you do have those, don't you?) &lt;br /&gt;and flow of questions chart. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Frankly, you probably want to get a questionaire package like RaoSoft &lt;br /&gt;and use it.  But if you have to use SQL, then get a normalized schema &lt;br /&gt;and use an encoding for the answers that can be expanded to several &lt;br /&gt;values as needed.  Consider multiple choice questions -- nobody like to &lt;br /&gt;do 300 questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116117891640197504?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116117891640197504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116117891640197504' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116117891640197504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116117891640197504'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/multiple-bit-data-type-in-table.html' title='Multiple bit data type in a table'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116074801704291744</id><published>2006-10-13T09:59:00.000-04:00</published><updated>2006-10-13T10:00:17.216-04:00</updated><title type='text'>need help with insert into table from two other tables</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a table with 3000 Client_id's. &lt;br /&gt;&lt;br /&gt;I have another table with 56 different order types.  The order types &lt;br /&gt;primary key is two fields (search_id, item_id) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need to insert into another table each client_id, along with each &lt;br /&gt;unique instance (56 instances) of search_id, item_id. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So the new table would have 3000 (client_id's) x 56 (distinct order &lt;br /&gt;types) = 168000 rows. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What would be the easiest to go about this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I have another table with 56 different order types.  The order types primary key is two fields [sic] (search_id, item_id)  I need to insert into another table each client_id, along with each unique instance (56 instances) of search_id, item_id. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The quick answer is to look up a CROSS JOIN.  You can materialize it or &lt;br /&gt;put it in a VIEW. &lt;br /&gt;&lt;br /&gt;But a better question is why are you doing this?  Does each row (NOT &lt;br /&gt;field) actually represent a fact in the reality of the data model? &lt;br /&gt;That is, does everyone really have all the order types?  My guess would &lt;br /&gt;be that you are printing out a form of some kind and want to show all &lt;br /&gt;the options to the users to get them to check off what they really use. &lt;br /&gt; Cross joins do not happen very often in the real world.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116074801704291744?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116074801704291744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116074801704291744' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074801704291744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074801704291744'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/need-help-with-insert-into-table-from.html' title='need help with insert into table from two other tables'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116074763058404264</id><published>2006-10-13T09:53:00.000-04:00</published><updated>2006-10-13T09:53:50.783-04:00</updated><title type='text'>Question About Revenue</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a reports table in my database where i am storing revenue &lt;br /&gt;collected for each particular month. &lt;br /&gt;&lt;br /&gt;Table structure &lt;br /&gt;ID       Int(4) &lt;br /&gt;Hotel Number  char(6) &lt;br /&gt;Month             char(1) &lt;br /&gt;Year               char(4) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;each row can be something like   1001, 1894, 1,2006 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need to write a query which should return text 'N/A' for months that dont &lt;br /&gt;contain data. For example if march 2006 has no revenue then it should return &lt;br /&gt;n/a. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can someone please assist me? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I have a reports table in my database where i am storing revenue collected for each particular month. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your narrative did not have a revenue column :)  We will ignore the &lt;br /&gt;fact that computing values and storing them in a table is a bad &lt;br /&gt;programming practice for OLTP apps and should only be done with a data &lt;br /&gt;warehouse app. &lt;br /&gt;&lt;br /&gt;CREATE TABLE ComputableSummary &lt;br /&gt;(hotel_nbr CHAR(6) NOT NULL &lt;br /&gt;  CHECK (??), &lt;br /&gt; year_month CHAR(7) NOT NULL &lt;br /&gt;   CHECK (year_month LIKE '[0-9][0-9][0-9][0-9]-[0-9][0-9]'), &lt;br /&gt; hotel_revenue DECIMAL(12,2) NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This next one can be part of a general Calendar table &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE ReportPeriods &lt;br /&gt;( cal_date DATETIME NOT NULL PRIMARY KEY, &lt;br /&gt;   year_month CHAR(7) NOT NULL &lt;br /&gt;   CHECK (year_month LIKE '[0-9][0-9][0-9][0-9]-[0-9][0-9]'), &lt;br /&gt;  etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I need to write a query which should return text 'N/A' for months that don't contain data.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT S.hotel_nbr,  R.year_month,  S.hotel_revenue &lt;br /&gt;  FROM ReportPeriods AS R &lt;br /&gt;             LEFT OUTER JOIN &lt;br /&gt;             ComputableSummary AS S &lt;br /&gt;            ON R.year_month = S.year_month &lt;br /&gt;WHERE .. ; &lt;br /&gt;&lt;br /&gt;And then following the basic rules of a tiered architecture, you would &lt;br /&gt;do the display in the front end for NULL revenues.  However, if you &lt;br /&gt;want to be a bad programmer, kludge it with: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;COALESCE (CAST(S.hotel_revenue AS CHAR(12)), 'N/A') AS revenus&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116074763058404264?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116074763058404264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116074763058404264' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074763058404264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074763058404264'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/question-about-revenue.html' title='Question About Revenue'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116074735943904734</id><published>2006-10-13T09:48:00.000-04:00</published><updated>2006-10-13T09:49:19.883-04:00</updated><title type='text'>Update Priority Field</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am trying to create a priority field to organize a list of tasks. &lt;br /&gt;The following 3 fields are being used: EventID (PK, int, not null), &lt;br /&gt;Name (nvarchar(50), not null), pri_ss (int, null). &lt;br /&gt;It would be nice if the code did several things at once: &lt;br /&gt;  1. Automitically add items to the list with the max pri_ss number + &lt;br /&gt;1. &lt;br /&gt;      (i.e. if you have 50 prioritized items in the list and you add &lt;br /&gt;another one, it adds it as pri_ss = 51) &lt;br /&gt;   2. If I change the priority of an item I would like the priority of &lt;br /&gt;all the numbers below it have 1 added to their initial number.  (i.e. &lt;br /&gt;if i change item 25 to item 5, i want item 5 to become item 6, and item &lt;br /&gt;6 to become item 7, and so on) &lt;br /&gt;My environment is SQL Server 2000, and i am somewhat fimiliar with. &lt;br /&gt;Any code from SQL experts would be a great help! &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Here is an old posting about manipulating such numberings: &lt;br /&gt;&lt;br /&gt;Given a motorpool with numbered parking spaces, you want to move the &lt;br /&gt;automobiles around. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Motorpool &lt;br /&gt;(parking_space INTEGER NOT NULL PRIMARY KEY &lt;br /&gt;   CHECK (parking_space &gt; 0), &lt;br /&gt; vin CHAR(17) NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Re-arrange the display order based on the parking_space column: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE SwapVehicles (@old_parking_space INTEGER, &lt;br /&gt;@new_parking_space INTEGER) &lt;br /&gt;AS &lt;br /&gt;UPDATE Motorpool &lt;br /&gt;   SET parking_space &lt;br /&gt;       = CASE parking_space &lt;br /&gt;         WHEN @old_parking_space &lt;br /&gt;         THEN @new_parking_space &lt;br /&gt;         ELSE parking_space + SIGN(@old_parking_space - @new_pos) &lt;br /&gt;         END &lt;br /&gt; WHERE parking_space BETWEEN @old_parking_space AND @new_parking_space &lt;br /&gt;    OR parking_space BETWEEN @new_parking_space AND @old_parking_space; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you want to drop a few rows, remember to close the gaps with this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE PROCEDURE CloseMotorpoolGaps() &lt;br /&gt;AS &lt;br /&gt;UPDATE Motorpool &lt;br /&gt;   SET parking_space &lt;br /&gt;       = (SELECT COUNT (M1.parking_space) &lt;br /&gt;            FROM Motorpool AS M1 &lt;br /&gt;           WHERE M1.parking_space &lt;= Motorpool.parking_space);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116074735943904734?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116074735943904734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116074735943904734' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074735943904734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116074735943904734'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/update-priority-field.html' title='Update Priority Field'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116016318094489040</id><published>2006-10-06T15:32:00.000-04:00</published><updated>2006-10-06T15:33:01.126-04:00</updated><title type='text'>append results of a simple select to table without a cursor?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I supect it can be done but I don't see it &lt;br /&gt;&lt;br /&gt;scenario: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;User  has Items and the first user is the Default user &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want all new Users to have the same list of  items as the default user &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Select * from Users &lt;br /&gt;right join Items &lt;br /&gt;on  User.UserID =  Items.UserID &lt;br /&gt;where User.LocalID = 0                -- This is the default user &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the above gets me  the list  of  x items  for the default Customer &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is it possible to append this list to Items for the new User, without using &lt;br /&gt;a cursor? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I want all new users to have the same list of  items as the default user &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it.  ISO-11179 prefers that you use collective or plural names for &lt;br /&gt;tables because they are sets, unless they really do model single &lt;br /&gt;entites.  Here is a skeleton of what you need: &lt;br /&gt;&lt;br /&gt;CREATE TABLE Users &lt;br /&gt;(user_id INTEGER DEFAULT 0 NOT NULL PRIMARY KEY &lt;br /&gt;  CHECK (user_id &gt;= 0), &lt;br /&gt; user_name VARCHAR(35) DEFAULT '{{DEFAULT}}' NOT NULL, --usps &lt;br /&gt;standard length &lt;br /&gt; etc.) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--set up the default user with little known trick &lt;br /&gt;INSERT INTO Users(user_id, user_name, ..) &lt;br /&gt;DEFAULT VALUES; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--table of items needed &lt;br /&gt;CREATE TABLE Items &lt;br /&gt;(item_nbr INTEGER NOT NULL PRIMARY KEY, -- needs standard code &lt;br /&gt; item_name VARCHAR(35) NOT NULL, &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- ownership is a relation so it has its own table! &lt;br /&gt;CREATE TABLE Ownership &lt;br /&gt;(user_id INTEGER NOT NULL &lt;br /&gt;     REFERENCES Users (user_id) &lt;br /&gt;     ON DELETE CASCADE &lt;br /&gt;     ON UPDATE CASCADE, &lt;br /&gt;item_nbr INTEGER NOT NULL &lt;br /&gt;     REFERENCES Items(item_nbr) &lt;br /&gt;     ON DELETE CASCADE &lt;br /&gt;     ON UPDATE CASCADE, &lt;br /&gt;PRIMARY KEY (user_id, item_name), &lt;br /&gt;etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- Now you need to proc to add new users and get them a default package &lt;br /&gt;to start &lt;br /&gt;CREATE PROCEDURE AddNewGuy &lt;br /&gt;(@new_user_id INTEGER, @new_user_name VARCHAR(35), etc.) &lt;br /&gt;AS &lt;br /&gt;BEGIN &lt;br /&gt;INSERT INTO Users (user_id, user_name, etc.) &lt;br /&gt;VALUES (@new_user_id, @new_user_name, etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Ownership &lt;br /&gt;SELECT @new_user_id, O.item_nbr &lt;br /&gt;   FROM Ownership AS O &lt;br /&gt;  WHERE O.user_id = 0; &lt;br /&gt;END; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Is it possible to append this list to Items for the new User, without using a cursor? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Of course.  Why did you even think of using a cursor?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116016318094489040?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116016318094489040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116016318094489040' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016318094489040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016318094489040'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/append-results-of-simple-select-to.html' title='append results of a simple select to table without a cursor?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116016311102641223</id><published>2006-10-06T15:29:00.000-04:00</published><updated>2006-10-06T15:31:51.176-04:00</updated><title type='text'>3 value logic. Why is SQL so special?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;3 value logic. Why is SQL so special?&lt;br /&gt;&lt;br /&gt;what would be the consequences of NULL=NULL being true? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;, what would be the consequences of NULL=NULL being true? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; NULL=NULL should not be true. &lt;br /&gt; NULL=NULL should not be false. &lt;br /&gt; NULL=NULL should not be UNKNOWN. &lt;br /&gt; NULL=NULL should be NULL. &lt;&lt; &lt;br /&gt;&lt;br /&gt;NULL is a missing *attribute* value; UNKNOWN is a *logical* value.  The &lt;br /&gt;first rule of NULLs is that they propagate.  You can easily set up &lt;br /&gt;contradictions that depend on the order evaluation when you have a &lt;br /&gt;BOOLEAN data type.  All SQLK data types must allow NULLs by definition. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NULL OR TRUE = NULL -- by definition &lt;br /&gt;UNKNOWN OR TRUE = TRUE -- by definition &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NULL AND TRUE = NULL -- by definition &lt;br /&gt;UNKNOWN AND TRUE = UNKNOWN -- by definition &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is why we have the  &lt;exp&gt; IS [NOT] [TRUE | FALSE |UNKNOWN] &lt;br /&gt;predicate in SQL-92&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116016311102641223?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116016311102641223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116016311102641223' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016311102641223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016311102641223'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/3-value-logic-why-is-sql-so-special.html' title='3 value logic. Why is SQL so special?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116016292462069956</id><published>2006-10-06T15:27:00.000-04:00</published><updated>2006-10-06T15:28:44.740-04:00</updated><title type='text'>Cursor Performance</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Cursor performance for a real world application. &lt;br /&gt;&lt;br /&gt;I have a table that holds records for a stops along a bus route.  Each &lt;br /&gt;records has a number of people getting on, number of people getting &lt;br /&gt;off, a spot check, and a current load column. &lt;br /&gt;The spot check column is the to verify that the sensors on the bus are &lt;br /&gt;working correctly; the most reliable number to be use in the is &lt;br /&gt;SPOT_CHECK. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Table Structure as follows: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ID (identity column) &lt;br /&gt;ROUTE (Description of the bus route) &lt;br /&gt;ONS (# of people getting on) &lt;br /&gt;OFFS (# of people getting off) &lt;br /&gt;SPOT_CHECK (visual spot count of people on the bus) &lt;br /&gt;LOAD (Calculated load on the bus) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ID  ROUTE  ONS OFFS SPOT_CHECK LOAD &lt;br /&gt;1   AAAA   5   0    null &lt;br /&gt;2   AAAA   0   0    null &lt;br /&gt;3   AAAA   2   1    null &lt;br /&gt;4   AAAA   0   2     5 &lt;br /&gt;5   AAAA   6   3     8 &lt;br /&gt;6   AAAA   0   5    null &lt;br /&gt;7   AAAA   1   2    null &lt;br /&gt;8   AAAA   0   1    null &lt;br /&gt;9   AAAA   0   1    null &lt;br /&gt;10  AAAA   0   0    null &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now, I want to calculate the load at each stop along the way. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Load = Previous stops load + current stop ONS - Current stop's OFFS if &lt;br /&gt;SPOT_CHECK is null, otherwise LOAD = SPOT_CHECK &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So the results of the above table will be as follows: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ID  ROUTE  ONS OFFS SPOT_CHECK LOAD &lt;br /&gt;1   AAAA   5   0    null       5 &lt;br /&gt;2   AAAA   0   0    null       5 &lt;br /&gt;3   AAAA   2   1    null       6 &lt;br /&gt;4   AAAA   0   2    5          5 &lt;br /&gt;5   AAAA   6   3    10         10 &lt;br /&gt;6   AAAA   0   5    null       5 &lt;br /&gt;7   AAAA   1   2    4          4 &lt;br /&gt;8   AAAA   0   1    null       3 &lt;br /&gt;9   AAAA   0   1    2          2 &lt;br /&gt;10  AAAA   0   2    null       0 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Current programming, we using a cursor and seeing much much slower &lt;br /&gt;performance than in our Oracle app.  Does anyone see a way of doing &lt;br /&gt;this load calculation without using a cursor and improving performance? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can't do simple sums of ons and offs to calculate load, because of &lt;br /&gt;the SPOT CHECK column. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I have a table that holds records [sic] for a stops along a bus route.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL and do not confuse records and rows. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; records [sic] has a number of people getting on, number of people getting off, a spot check, and a current load column. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The current load is a computed column and we do not store such &lt;br /&gt;computations in a good schema design. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; The spot check column is the to verify that the sensors on the bus are working correctly; the most reliable number to be use in the is spot_check&lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why did you use a vague, magical, non-relational, universal "id" column &lt;br /&gt;instead of a relational key?  The stops are a known attribute of a &lt;br /&gt;route, but you left them out of the data model in spite of talking &lt;br /&gt;about them. &lt;br /&gt;&lt;br /&gt;CREATE TABLE BusTraffic &lt;br /&gt;(route_nbr INTEGER NOT NULL , &lt;br /&gt; stop_nbr INTEGER NOT NULL, &lt;br /&gt; bus_nbr  INTEGER NOT NULL &lt;br /&gt;   REFERENCES Buses(bus_nbr), &lt;br /&gt; PRIMARY KEY (route_nbr, stop_nbr), &lt;br /&gt; boarding_cnt  INTEGER DEFAULT 0 NOT NULL, &lt;br /&gt; disembark_cnt  INTEGER DEFAULT 0 NOT NULL, &lt;br /&gt; spotcheck_cnt INTEGER -- null means not done &lt;br /&gt; ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;other stuff not shown might be .. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Buses &lt;br /&gt;(bus_nbr  INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; bus_capacity  INTEGER NOT NULL, &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Now, I want to calculate the load at each stop along the way...  I can't do simple sums of ons and offs to calculate load, because of the SPOT CHECK column. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Probably something like this &lt;br /&gt;&lt;br /&gt;SELECT T2.route_nbr, T2.stop_nbr, &lt;br /&gt;             SUM (CASE WHEN spotcheck_cnt IS NULL &lt;br /&gt;                          THEN (boarding_cnt  - disembark_cnt) &lt;br /&gt;                        ELSE spotcheck_cnt END) AS bus_load, &lt;br /&gt;            (CASE WHEN spotcheck_cnt IS NULL &lt;br /&gt;                          THEN 'spot checked' &lt;br /&gt;                        ELSE 'computed' END) AS verification &lt;br /&gt;  FROM  BusTraffic AS T1, BusTraffic AS T2 &lt;br /&gt; WHERE T1.route_nbr = T2.route_nbr &lt;br /&gt;    AND T1.stop_nbr &lt;= T2.stop_nbr; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you can use the OLAP SUM() OVER() functions in SQL, this will be &lt;br /&gt;easier and faster than a self-join.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116016292462069956?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116016292462069956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116016292462069956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016292462069956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016292462069956'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/cursor-performance.html' title='Cursor Performance'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116016274787664336</id><published>2006-10-06T15:24:00.000-04:00</published><updated>2006-10-06T15:25:56.016-04:00</updated><title type='text'>scramble ssn with sql server</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm trying to scramble the ssn#s within our database.  I would need a 9 &lt;br /&gt;digit number to be converted into another 9 digit number in our dev &lt;br /&gt;database. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Example #1: &lt;br /&gt;ssn: 123456789 converts to 987654321 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also there is a catch, there is a possibility that there could be &lt;br /&gt;duplicate ssn within a table due to bad data.  I was the 2 records with &lt;br /&gt;the same actual ssn# to be converted into the same scrambled ssn# using &lt;br /&gt;sql server (so that the scrambled ssn#s match) for this issue. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is there a way to do this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; create table SSN_MASK &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(EW_SSN integer identity primary key not null, &lt;br /&gt;OLD_SSN varchar(9));  -- not sure how you defined it &lt;&lt; &lt;br /&gt;&lt;br /&gt;SSN is always CHAR(9).  Simply numbering it with a proprietary feature &lt;br /&gt;is not that good; you have destroyed the data type.  Here is one we &lt;br /&gt;used in procedural code with arrays. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE SSN_masks &lt;br /&gt;(shift_id INTEGER NOT NULL PRIMARY KEY -- cols 8 &amp; 9 &lt;br /&gt;    CHECK (shift_id BETWEEN 00 AND 99), &lt;br /&gt; col1 INTEGER NOT NULL, &lt;br /&gt; col2 INTEGER NOT NULL, &lt;br /&gt; col3 INTEGER NOT NULL, &lt;br /&gt; col4 INTEGER NOT NULL, &lt;br /&gt; col5 INTEGER NOT NULL, &lt;br /&gt; col6 INTEGER NOT NULL, &lt;br /&gt; col7 INTEGER NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You take the last two digits of the SSN (fastest changing values) and &lt;br /&gt;look up a vector that tells you how to shift the remaining seven &lt;br /&gt;digits. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;shift(x) =  ABS((x + col_n) % 11-10) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since you have 100 different masks, the data gets scrambled pretty good &lt;br /&gt;and it destroys the area digits which would otherwise repeat and give &lt;br /&gt;information about the population geographic distribution.  This is also &lt;br /&gt;reversible because we preserve the shift identifier in the output; &lt;br /&gt;shift all of them and it is a bitch to unscramble without the shift &lt;br /&gt;array.  Then you change the array when you get the next sample.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116016274787664336?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116016274787664336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116016274787664336' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016274787664336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116016274787664336'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/scramble-ssn-with-sql-server.html' title='scramble ssn with sql server'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116005520824740949</id><published>2006-10-05T09:31:00.000-04:00</published><updated>2006-10-05T09:33:28.353-04:00</updated><title type='text'>Table with Foreign and running total</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;sql server noob here. class Relational DB question - I   wanted to see &lt;br /&gt;if my thinking is right and bounce this very simple design question off &lt;br /&gt;you guys.. In particular using ASP.NET as the client and wanted to know &lt;br /&gt; if I should address this on the db side or the client/business layer &lt;br /&gt;side. &lt;br /&gt;&lt;br /&gt;3 tables: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Master: &lt;br /&gt;ssn varchar (10) (PK) &lt;br /&gt;phone nchar(10) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Detail &lt;br /&gt;ssn varchar (10) FK ? &lt;br /&gt;datetime datetime   ? &lt;br /&gt;amt numeric &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Totals: &lt;br /&gt;ssn varchar (10) FK &lt;br /&gt;amt numeric   (should hold a running total by ssn of detail.amt) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Whenever a new detail record is entered, of course the master key must &lt;br /&gt;be there, I want to keep Totals.amt current by ssn. Three questions: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. What's the best way to keep Totals current? A trigger? Call it &lt;br /&gt;automatically using db dependendancy setup? would dotNet or ADO.net &lt;br /&gt;need to know or do anything. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. I have not tried, but I can set up a compound unique key for detail &lt;br /&gt;that covers ssn and datetime right? and can ssn still be a foreign key &lt;br /&gt;to Master?  That did not seem trivial in sql server 2000.. at a high &lt;br /&gt;level how? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. I've know some look down on the idea of running totals living inside &lt;br /&gt;the db, afterall Totals.amt can be calculated at any given time. I've &lt;br /&gt;seen in other designs like this, Is this terribly unacceptable? Even if &lt;br /&gt;a poor design, I'm still looking for how to maintain integrity for this &lt;br /&gt;design. Also wonder, would it be terrible to maintain integrity with &lt;br /&gt;client code? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you have any code or samples that would be greatly appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;CREATE TABLE Callers &lt;br /&gt;(ssn CHAR(9) NOT NULL PRIMARY KEY, --you got the size wrong! &lt;br /&gt; phone_nbr CHAR(10) NOT NULL -- us only, fixed length? &lt;br /&gt; ); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE CallLog &lt;br /&gt;(ssn CHAR(9) NOT NULL &lt;br /&gt;    REFERENCES Callers(ssn) &lt;br /&gt;    ON UPDATE CASCADE, &lt;br /&gt; call_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt; call_amt DEICMAL (8,2) NOT NULL &lt;br /&gt; PRIMARY KEY (ssn, call_time)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW CallerAcctTotals (ssn, caller_amt_tot) &lt;br /&gt;AS &lt;br /&gt;SELECT C.ssn, COALESCE (SUM(L.caller_amt), 0.00) &lt;br /&gt;  FROM Callers AS C &lt;br /&gt;             LEFT OUTER JOIN &lt;br /&gt;             CallLog AS L &lt;br /&gt;             ON C.ssn = L.ssn &lt;br /&gt; GROUP BY C.ssn; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Whenever a new detail record [sic] is entered, of course the master key must &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;be there, I want to keep Totals.amt current by ssn. &lt;&lt; &lt;br /&gt;&lt;br /&gt;Rows are not records-- nothing like them at all.  Youa re still &lt;br /&gt;thinking in terms of files -- names like Master and Details really show &lt;br /&gt;that mindset -- tape file terms! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; 1. What's the best way to keep Totals current? A trigger? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Triggers?  You mean proceudral file system code!  No, use a VIEW that &lt;br /&gt;will always be up to date when it is invoked, not an other file thinly &lt;br /&gt;disguised as a table. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; 2. I have not tried, but I can set up a compound unique key for detail that covers ssn and datetime right? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DATETIME is a reserved word and tooooo vague to be a data element name. &lt;br /&gt; And, yes these two columns should be the key for the log of calls &lt;br /&gt;made. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; can ssn still be a foreign key to Callers? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;See DDL for use of UNIQUE() &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; 3. I've know some look down on the idea of running totals living inside the db, afterall Totals.amt can be calculated at any given time. I've seen in other designs like this, Is this terribly unacceptable? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Might okay for a data warehouse, but not for a production DB. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Even if a poor design, I'm still looking for how to maintain integrity for this design. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Constantly firing triggers that will drag performance into the ground &lt;br /&gt;and kill it when it gets to production size &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Also wonder, would it be terrible to maintain integrity with client code? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;YES.  That defeats the whole purpose of RDBMS as the one central tool &lt;br /&gt;for data integrity.  The minute someone uses QA or another tool to get &lt;br /&gt;around you app code, the game is over.  Oh, and how did you plan on &lt;br /&gt;being sure that ALL zillion app programs do integrity checks the same &lt;br /&gt;way?  or at all? &lt;br /&gt;&lt;br /&gt;SQL is declarative and not procedural.  Your whole approach is wrong.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116005520824740949?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116005520824740949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116005520824740949' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005520824740949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005520824740949'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/table-with-foreign-and-running-total.html' title='Table with Foreign and running total'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116005457728597618</id><published>2006-10-05T09:21:00.000-04:00</published><updated>2006-10-05T09:22:57.403-04:00</updated><title type='text'>Creating a view do display normalised data flattened</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have created the following schema to illustrate my question: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[tblCustomerProperty] ( &lt;br /&gt;        [cpcusID] [int] NOT NULL , &lt;br /&gt;        [cpproID] [int] NOT NULL , &lt;br /&gt;        [cpValue] [varchar] (50) COLLATE Latin1_General_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[tblCustomers] ( &lt;br /&gt;        [cusID] [int] IDENTITY (1, 1) NOT NULL , &lt;br /&gt;        [cusName] [varchar] (100) COLLATE Latin1_General_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[tblProperties] ( &lt;br /&gt;        [proID] [int] NOT NULL , &lt;br /&gt;        [proName] [varchar] (50) COLLATE Latin1_General_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ALTER TABLE [dbo].[tblCustomers] WITH NOCHECK ADD &lt;br /&gt;        CONSTRAINT [PK_tblCustomers] PRIMARY KEY  CLUSTERED ([cusID])  ON &lt;br /&gt;[PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ALTER TABLE [dbo].[tblProperties] WITH NOCHECK ADD &lt;br /&gt;        CONSTRAINT [PK_tblProperties] PRIMARY KEY  CLUSTERED ([proID])  ON &lt;br /&gt;[PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ALTER TABLE [dbo].[tblCustomerProperty] ADD &lt;br /&gt;        CONSTRAINT [FK_tblCustomerProperty_tblCustomers] FOREIGN KEY &lt;br /&gt;([cpcusID]) REFERENCES [dbo].[tblCustomers] ([cusID]) ON DELETE CASCADE &lt;br /&gt;, &lt;br /&gt;        CONSTRAINT [FK_tblCustomerProperty_tblProperties] FOREIGN KEY &lt;br /&gt;([cpproID]) REFERENCES [dbo].[tblProperties] ([proID]) ON DELETE &lt;br /&gt;CASCADE &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is essentially a very normalized customer database.  A number of &lt;br /&gt;properties are defined in the tblProperties table.  One record per &lt;br /&gt;customer exists in the tblCustomer table, and one record per &lt;br /&gt;customer/property combination exists in the tblCustomerProperty table. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I imagine this is fairly common in systems that need to be highly &lt;br /&gt;configurable.  Obviously it comes with it's performance overheads but &lt;br /&gt;it's very flexible. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Assume the following data &lt;br /&gt;INSERT INTO tblProperties(proID, proName) VALUES(1, 'Occupation') &lt;br /&gt;INSERT INTO tblProperties(proID, proName) VALUES(2, 'Email') &lt;br /&gt;INSERT INTO tblCustomers(cusName) VALUES('Fred Bloggs') &lt;br /&gt;DECLARE @ID int &lt;br /&gt;SELECT @ID = @@IDENTITY &lt;br /&gt;INSERT INTO tblCustomerProperty(cpcusID, cpproID, cpValue) VALUES(@ID, &lt;br /&gt;1, 'Computer Engineer') &lt;br /&gt;INSERT INTO tblCustomerProperty(cpcusID, cpproID, cpValue) VALUES(@ID, &lt;br /&gt;2, '...@bloggs.com') &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My question is how can I create a view that will return a flat view of &lt;br /&gt;customers?  The view needs to dynamically include 'columns' specified &lt;br /&gt;in the tblProperties table without having to be changed. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;eg. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;cusID   cusName   Occupation   Email &lt;br /&gt;1        Fred Bloggs   Computer Engineer   f...@bloggs.com &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Many thanks! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; This is essentially a very normalized customer database. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Not only is it un-normalized (it never made it to normalized to be &lt;br /&gt;denormalized!), it is full of ISO-11179 violations, lack of relational &lt;br /&gt;keys, data and meta-data are mixed, etc. &lt;br /&gt;&lt;br /&gt;What you have is called a EAV (entity-attribute-value) design flaw.  It &lt;br /&gt;is a very common design error among people who were asleep in their &lt;br /&gt;database classes :)  Google it; it is a disaster that will fall apart &lt;br /&gt;from the lack of data integrity in about one year of production work. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also, get rid of that silly "tbl-" prefix and camel case -- it makes &lt;br /&gt;you look like an OO programmer who does not know that even MS gave up &lt;br /&gt;on camel case and Hungarian notation. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Seriously, you need to start over from scratch with a real data model &lt;br /&gt;instead a vague "thingies have properties" view of the world.  "To be &lt;br /&gt;is to be something in particular; to be nothign in particular or &lt;br /&gt;everything in general is to be Nothing" -- Aristotle&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116005457728597618?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116005457728597618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116005457728597618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005457728597618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005457728597618'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/creating-view-do-display-normalised.html' title='Creating a view do display normalised data flattened'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-116005445312255597</id><published>2006-10-05T09:19:00.000-04:00</published><updated>2006-10-05T09:20:53.583-04:00</updated><title type='text'>Using GO in stored proc</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I need to alter a temp table to add column, and then access that column &lt;br /&gt;in next line.As it cant be possible in a same batch , I need to put a &lt;br /&gt;GO  between the lines.But the problem is, these are the lines of a &lt;br /&gt;stored proc,and as soos as query analyzer(sqlserver2000) finds a GO,it &lt;br /&gt;takes it as a last line of the stored proc. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Can't I  add column and access the same in a same sp?Is it technically &lt;br /&gt;possible? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Should you have any comments or any other work around , pls share with &lt;br /&gt;me. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Apologies for any inconvenience in understnding the above points. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;thanks, &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; Should you have any comments or any other work around , pls share with me. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Do not program this way at all.  This is like wanting to modify an &lt;br /&gt;automobile in the middle of a race.  You should start the race with a &lt;br /&gt;complete car and not create it on the fly.  Temp tables are also a &lt;br /&gt;symptom of a procedural approach to a problem rather than a relational &lt;br /&gt;approach. &lt;br /&gt;&lt;br /&gt;Until we have actual specs (i.e. What you want to do) instead of a &lt;br /&gt;kludge request (I.e. how you have decided to do it already), we cannot &lt;br /&gt;help you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-116005445312255597?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/116005445312255597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=116005445312255597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005445312255597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/116005445312255597'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/10/using-go-in-stored-proc.html' title='Using GO in stored proc'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115944889668233462</id><published>2006-09-28T09:07:00.000-04:00</published><updated>2006-09-28T09:08:16.860-04:00</updated><title type='text'>Using Variables &amp; Updating tbl: Update STATUS field from CASE exp</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I need help. &lt;br /&gt;I am fairly new in declaring variables &amp; can be put into one SP. &lt;br /&gt;&lt;br /&gt;--&gt; Update the [Status] aliased as OLD to the [NEW] value pulled from a CASE &lt;br /&gt;statement. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[MyTable] table to update &lt;br /&gt;[NEW] (PULLS NEW VALUES BY USING CASE EXPRESSIONS) &lt;br /&gt;[OLD] (VALUE IN MYTABLE NEEDING UPDATING) &lt;br /&gt;[Expire Date] Column in MyTable &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-- This is what I have so far.. : &lt;br /&gt;SELECT     Status AS OLD, (CASE WHEN [Expire Date] &lt; GETDATE() THEN &lt;br /&gt;'Expired' ELSE CASE WHEN [Expire Date] &gt;= getdate() &lt;br /&gt;                      THEN 'Active' ELSE 'undefined' END END) AS NEW &lt;br /&gt;FROM         MyTable &lt;br /&gt;WHERE     (Status &lt;&gt; (CASE WHEN [Expire Date] &lt; GETDATE() THEN 'Expired' &lt;br /&gt;ELSE CASE WHEN [Expire Date] &gt;= getdate() &lt;br /&gt;                      THEN 'Active' ELSE 'UNK' END END)) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to &lt;br /&gt;-have one SP to declare these as variables &lt;br /&gt;-Then update the table to something like this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE MyTable &lt;br /&gt;Set @Old = @New &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--- &lt;br /&gt;CREATE TABLE MyTable( &lt;br /&gt;        [ID] [int] IDENTITY(1,1) &lt;br /&gt;        [Status] [char](10), &lt;br /&gt;        [Expire Date] [datetime]) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;is this what you meant to post so as to have a valid name, with proper &lt;br /&gt;data element names? &lt;br /&gt;&lt;br /&gt;CREATE TABLE Items &lt;br /&gt;(item_id INTEGER NOT NULL PRIMARY KEY, &lt;br /&gt; expiry_date DATETIME NOT NULL, &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Unlike a deck of punch cards, we can use a VIEW (or a computed column &lt;br /&gt;if you really want to be proprietary instead of portable and &lt;br /&gt;maintainable): &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW ItemStatus(item_id, .., item_status) &lt;br /&gt;AS &lt;br /&gt;SELECT item_id, .., &lt;br /&gt;       CASE WHEN expiry_date &lt; CURRENT_TIMESTAMP &lt;br /&gt;            THEN 'expired' ELSE 'active' END &lt;br /&gt;  FROM Items; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Your syntax for the CASE expression was wrong.  The 'unk' path will not &lt;br /&gt;be executed unless you have NULLs, which I assume that you do not. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You are approaching this problem as if you were using punch cards that &lt;br /&gt;have to PHYSICALLY store the data.  Your "old" and "new" (reserved &lt;br /&gt;words in SQL!) look like tapes in a 1950's file merge program. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Start thinking LOGICALLY, with predicates and not procedures.  Start &lt;br /&gt;using Standard SQL -- SQL Server has most of SQL-92 these days; &lt;br /&gt;CURRENT_TIMESTAMP and not the old UNIX-based getdate().  Read ISO-11179 &lt;br /&gt;and learn how to name data elements. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Reply&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115944889668233462?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115944889668233462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115944889668233462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944889668233462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944889668233462'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/using-variables-updating-tbl-update.html' title='Using Variables &amp; Updating tbl: Update STATUS field from CASE exp'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115944880933484025</id><published>2006-09-28T09:06:00.000-04:00</published><updated>2006-09-28T09:06:49.713-04:00</updated><title type='text'>For SQL Buffs</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have MyTable (ID, BUSINESS_UNIT_ID, CUSTOMER_NUMBER).  I need a list &lt;br /&gt;of customer numbers that exist in more than one BUSINESS_UNIT_ID. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  I have MyTable (ID, BUSINESS_UNIT_ID, CUSTOMER_NUMBER). &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;My guess is that "id" is a totally redundant, non-relational rowing &lt;br /&gt;numbers that newbies who never read anything on RDBMS use.  Did you &lt;br /&gt;mean &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE CustomerAssignments &lt;br /&gt;(business_unit INTEGER NOT NULL &lt;br /&gt;   REFERENCES OrgChart(business_unit_id) &lt;br /&gt;  ON UPDATE CASCADE, &lt;br /&gt; customer_id NTEGER NOT NULL &lt;br /&gt;  REFERENCES Customers (customer_id) &lt;br /&gt;  ON UPDATE CASCADE &lt;br /&gt;  ON  DELETE CASCADE , &lt;br /&gt;PRIMARY KEY (business_unit_id, customer_id)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  I need a list of customer numbers that exist in more than one BUSINESS_UNIT_ID.&lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT customer_id &lt;br /&gt;  FROM CustomerAssignments &lt;br /&gt;GROUP BY customer_id &lt;br /&gt;HAVING COUNT(*) &gt; 1; &lt;br /&gt;&lt;br /&gt;Without the key, you would have to use COUNT(DISTINCT business_unit_id)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115944880933484025?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115944880933484025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115944880933484025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944880933484025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944880933484025'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/for-sql-buffs.html' title='For SQL Buffs'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115944833919095643</id><published>2006-09-28T08:58:00.000-04:00</published><updated>2006-09-28T08:59:38.343-04:00</updated><title type='text'>Good Technique For Removing Dupes?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a table full of records, some of which are duplicates &lt;br /&gt;and I need to go through the table and remove the duplicate records. &lt;br /&gt;My technique works, but it is extremely slow, and I was wondering if &lt;br /&gt;anyone can tell me a faster method. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         Here is a description of my current technique: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.    Declare a cursor and fetch all fields from first record from &lt;br /&gt;TABLE1. &lt;br /&gt;2.    SELECT COUNT(*) &lt;br /&gt;       FROM TABLE1 &lt;br /&gt;       WHERE Field1 = @Value1, Field2 = @Value2 &lt;br /&gt;3.    If COUNT &lt;= 1 THEN &lt;br /&gt;            This is not a duplicate record, go to the next record &lt;br /&gt;       ELSE &lt;br /&gt;       BEGIN &lt;br /&gt;             Must be a duplicate record. &lt;br /&gt;             DELETE FROM TABLE 1 where Field3  &lt;&gt; @Value 3 &lt;br /&gt;             Go to the next record. &lt;br /&gt;       END &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        I am wondering if attempting to delete a record from the table &lt;br /&gt;while it is being looped through and SELECTED from is causing it to be &lt;br /&gt;unusually slow. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        Does anyone have a different and possibly faster de-duping &lt;br /&gt;algorithm? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;   I have a table full of records [sic], some of which are duplicates and I need to go through the table and remove the duplicate records  [sic]. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1)  Rows are not records; tables are not files, nor are columns &lt;br /&gt;anything like fields.  You are in trouble now because you did not &lt;br /&gt;bother with the constraints that you needed. As soon as you scrub this &lt;br /&gt;data, add those constraints and quit implementing files in SQL. &lt;br /&gt;&lt;br /&gt;2) If you want to use cursors, then look up the "DELETE FROM [table &lt;br /&gt;name] .. WHERE CURRENT OF [cursor] ;"  syntax. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Your pseudo_code was a bit vague as to what makes a duplicate so I &lt;br /&gt;would guess  something like this will work: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DELETE FROM Table1 &lt;br /&gt;  WHERE field3 &lt; &lt;br /&gt;          (SELECT MAX(field3) FROM Table_1 AS T2 &lt;br /&gt;                WHERE Table_1.field1 = T2.field1 &lt;br /&gt;                   AND Table_1.field2 = T2.field2 ; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This says find groupings based on (field1, field2) and keep the single &lt;br /&gt;rows that have the max value in field3.  Pretty common problem when &lt;br /&gt;clenang out a history and fiedl3 is a datetime.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115944833919095643?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115944833919095643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115944833919095643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944833919095643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115944833919095643'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/good-technique-for-removing-dupes.html' title='Good Technique For Removing Dupes?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115877449065222735</id><published>2006-09-20T13:47:00.000-04:00</published><updated>2006-09-20T13:48:11.136-04:00</updated><title type='text'>Time recording query</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Here is an interesting problem: &lt;br /&gt;Lets say I own some imaginary company. Like for all companies, my &lt;br /&gt;employees report their time to some time reporting application. &lt;br /&gt;Following table stores these time recording activities: &lt;br /&gt;&lt;br /&gt;EmpId    Date    Project    No_of_hours &lt;br /&gt;1            08/01     P1              4 &lt;br /&gt;1            08/01     P2              3 &lt;br /&gt;1            08/01     P3              1 &lt;br /&gt;1            08/02     P3              7 &lt;br /&gt;1            08/02     P1              1 &lt;br /&gt;1            08/03     P1              4 &lt;br /&gt;1            08/03     P1              4 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- In given month, employees spend hours on multiple projects &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to write a query which entering the begin and end dates and the &lt;br /&gt;emp id will return the projects the employee worked on during that &lt;br /&gt;period and the no_of_hours he worked on each &lt;br /&gt;Output I am looking should be something similar to this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;EmpId  Project   No_of_hours &lt;br /&gt;1            P1              30 &lt;br /&gt;1            P2              15 &lt;br /&gt;1            P3              20 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any  help is appreciated ... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;The start and stop times are what you should have been catching in the &lt;br /&gt;first place and not the computed hours.  Think raw data and single &lt;br /&gt;facts when designing a table. Let me use a history table for price &lt;br /&gt;changes.  The fact to store is that a price had a duration: &lt;br /&gt;&lt;br /&gt;CREATE TABLE PriceHistory &lt;br /&gt;(upc CHAR(13) NOT NULL &lt;br /&gt;  REFERENCES Inventory(upc), &lt;br /&gt; start_date DATE NOT NULL, &lt;br /&gt; end_date DATE, -- null means current &lt;br /&gt; CHECK(start_date &lt; end_date), &lt;br /&gt; PRIMARY KEY (upc, start_date), &lt;br /&gt; item_price DECIMAL (12,4) NOT NULL &lt;br /&gt;  CHECK (item_price &gt; 0.0000), &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You actually needs more checks to assure that the start date is at &lt;br /&gt;00:00 and the end dates is at 23:59:59.999 Hrs.  You then use a BETWEEN &lt;br /&gt;predicate to get the appropriate price. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT .. &lt;br /&gt;  FROM PriceHistory AS H, Orders AS O &lt;br /&gt; WHERE O.sales_date BETWEEN H.start_date &lt;br /&gt;           AND COALESCE (end_date, CURRENT_TIMESTAMP); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It is also a good idea to have a VIEW with the current data: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW CurrentPrices (..) &lt;br /&gt;AS &lt;br /&gt;SELECT .. &lt;br /&gt;  FROM PriceHistory &lt;br /&gt; WHERE end_date IS NULL;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115877449065222735?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115877449065222735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115877449065222735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115877449065222735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115877449065222735'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/time-recording-query.html' title='Time recording query'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115877393847050903</id><published>2006-09-20T13:38:00.000-04:00</published><updated>2006-09-20T13:39:02.940-04:00</updated><title type='text'>SQL Query - A better way?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have a query that I have written and it works, but it seems a bit &lt;br /&gt;redundant and I am wondering if there is a better way to write it. &lt;br /&gt;&lt;br /&gt;My basic problem is I want to pull only 1 record, and that record is &lt;br /&gt;the newest one based on the LASTUPDATE date field. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is my attempt at the query &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT * FROM ACTION_HISTORY &lt;br /&gt;WHERE CASE_ID = '534623' &lt;br /&gt;AND EVENTNAME='AssignedChanged' &lt;br /&gt;AND LASTUPDATE = ( SELECT MAX(LASTUPDATE) FROM ACTION_HISTORY WHERE &lt;br /&gt;CASE_ID = '534623' AND EVENTNAME='AssignedChanged') &lt;br /&gt;ORDER BY LASTUPDATE DESC; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; My basic problem is I want to pull only 1 record [sic], and that record [sic] is the newest one based on the LASTUPDATE date field  [sic]. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You are confusing rows and records, fields and columns, so yoiu wind up &lt;br /&gt;with a data model that shows events and not facts.  Each row should be &lt;br /&gt;complete fact, and temporal facts have durations. &lt;br /&gt;&lt;br /&gt;Let me use a history table for price changes.  The fact to store is &lt;br /&gt;that a price had a duration: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE PriceHistory &lt;br /&gt;(upc CHAR(13) NOT NULL &lt;br /&gt;  REFERENCES Inventory(upc), &lt;br /&gt; start_date DATE NOT NULL, &lt;br /&gt; end_date DATE, -- null means current &lt;br /&gt; CHECK(start_date &lt; end_date),  -- actaualloy needs more checks &lt;br /&gt; PRIMARY KEY (upc, start_date), &lt;br /&gt; item_price DECIMAL (12,4) NOT NULL &lt;br /&gt;  CHECK (item_price &gt; 0.0000), &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You then use a BETWEEN predicate to get the appropriate price. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT .. &lt;br /&gt;  FROM PriceHistory AS H, Orders AS O &lt;br /&gt; WHERE O.sales_date BETWEEN H.start_date &lt;br /&gt;           AND COALESCE (end_date, CURRENT_TIMESTAMP); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It is also a good idea to have a VIEW with the current data: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW CurrentPrices (..) &lt;br /&gt;AS &lt;br /&gt;SELECT .. &lt;br /&gt;  FROM PriceHistory &lt;br /&gt; WHERE end_date IS NULL;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115877393847050903?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115877393847050903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115877393847050903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115877393847050903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115877393847050903'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/sql-query-better-way.html' title='SQL Query - A better way?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115875729120063770</id><published>2006-09-20T09:00:00.000-04:00</published><updated>2006-09-20T09:01:31.310-04:00</updated><title type='text'>SORT THE PHYSICAL ORDER ON A TABLE'S COLUMNS</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm working in SQL2000 . how can I move the physical position of a column   &lt;br /&gt;in a table by script? &lt;br /&gt;for example: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;select * from table1 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;f1      f2      f3 &lt;br /&gt;---- ----- ----- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;desired result: &lt;br /&gt;f3      f2      f1 &lt;br /&gt;---- ----- ----- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;any help would be greatly appreciated. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; how can I move the physical position of a column  in a table by script? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You have the wrong mental model of how RDBMS and SQL work.  Think &lt;br /&gt;logical and not physical models. &lt;br /&gt;&lt;br /&gt;One of the many reasons that columns are not like fields is that they &lt;br /&gt;have no physical location and are not required to be contigous.  You &lt;br /&gt;use a column name to get their data. Likewise, the rows in a table have &lt;br /&gt;no ordering, unlike the records in a file.  You locate them by a key. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; In a file system, 3GL commands like "READ (a,b,c) FROM FileA" give you &lt;br /&gt;different results than "READ (c,a,b) FROM FileA" while "SELECT a,b,c &lt;br /&gt;FROM TableA" has the same data as "SELECT c,a,b FROM TableA".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115875729120063770?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115875729120063770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115875729120063770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115875729120063770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115875729120063770'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/sort-physical-order-on-tables-columns.html' title='SORT THE PHYSICAL ORDER ON A TABLE&apos;S COLUMNS'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115875720486133081</id><published>2006-09-20T08:59:00.000-04:00</published><updated>2006-09-20T09:00:05.233-04:00</updated><title type='text'>What am I missing with this simple query?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am trying to add the results of this query to a new table using the &lt;br /&gt;procedure below: &lt;br /&gt;&lt;br /&gt;INSERT into db.TempCheckHistGN (EmpID,GrossPay,NetPay) &lt;br /&gt;SELECT EmployeeID, SUM(GrossPay), as Expr1, Sum(NetPay) as Expr2 FROM &lt;br /&gt;dbo.tblPACheckHist &lt;br /&gt;WHERE (CheckDate Between '11/1/2005' AND '12/31/2010') AND (EmployeeID &gt;='' &lt;br /&gt;AND EmployeeID &lt;='zzzzzz') &lt;br /&gt;GROUP BY EmployeeID &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I get a duplicate key error (EmpID is the key) but I shouldn't since the &lt;br /&gt;records are being summed by EmployeeID &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Are the two data elements emp_id and employee_id actually the same data &lt;br /&gt;element?  If so, then use the same name for them.  If not, check that &lt;br /&gt;they converted properly on insertion. Let's clean up the code a bit &lt;br /&gt;- ISO-8601 dates, consistent use of BETWEEN and removal of silly &lt;br /&gt;prefixes, etc: &lt;br /&gt;&lt;br /&gt;INSERT INTO db.TempCheckHistgn (emp_id, gross_pay, net_pay) &lt;br /&gt;SELECT emp_id, SUM(gross_pay), SUM(net_pay) &lt;br /&gt;  FROM dbo.PayCheckHistory &lt;br /&gt; WHERE check_date BETWEEN '2005-11-01' AND '2010-31-2010' &lt;br /&gt;   AND emp_id BETWEEN '' AND 'ZZZZZZ' -- is this redundant? &lt;br /&gt; GROUP BY emp_id; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I get a duplicate key error (emp_id is the key) but I shouldn't since the records [sic] are being summed by emp_id.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Making a guess at the DDL that you did not post, I would assume that &lt;br /&gt;the INSERT INTO has been run twice.  I would also guess that emp_id &lt;br /&gt;BETWEEN '' AND 'ZZZZZZ' covers all the personnel identifiers, but &lt;br /&gt;there might ones with numerics and perhaps the all-blank one is &lt;br /&gt;special. It looks weird, tho.   That predicate looks more like a &lt;br /&gt;CHECK() than a search condition. &lt;br /&gt;&lt;br /&gt;You talked about "records"; you materialize and store computed &lt;br /&gt;data; this is a symptom of still having a file system mindset.  This &lt;br /&gt;problem used to happen in file systems when the same transaction tape &lt;br /&gt;was hung by the next shift. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the relational world, we avoid temp tables of all kinds by using &lt;br /&gt;virtual tables, such as a VIEW, which is guaranteed to be up-to-date &lt;br /&gt;when it is invoked: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW PaycheckHistorySummary (emp_id, gross_pay_tot, net_pay_tot) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AS &lt;br /&gt;SELECT emp_id, SUM(gross_pay), SUM(net_pay) &lt;br /&gt;  FROM dbo.PaycheckHistory &lt;br /&gt; WHERE check_date BETWEEN '2005-11-01' AND '2010-31-2010' &lt;br /&gt;   AND emp_id BETWEEN '' AND 'ZZZZZZ' -- is this redundant? &lt;br /&gt; GROUP BY emp_id;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115875720486133081?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115875720486133081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115875720486133081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115875720486133081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115875720486133081'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/what-am-i-missing-with-this-simple.html' title='What am I missing with this simple query?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791403740470981</id><published>2006-09-10T14:46:00.000-04:00</published><updated>2006-09-10T14:47:17.610-04:00</updated><title type='text'>Delete with inner join</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;Is this the proper way of doing a join in a delete or update? &lt;br /&gt;Is the a better way? &lt;br /&gt;delete useraccount where useraccountid in ( &lt;br /&gt;select useraccountid &lt;br /&gt;from UserAccount with (nolock ) &lt;br /&gt;inner join employee with (nolock) on employee.personId = UserAccount.PersonId &lt;br /&gt;where EmployerId =66 ) &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  Is this the proper way of doing a join in a delete or update? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There is no proper way of oing a join in a delete or update; that &lt;br /&gt;syntax is proprietary and subject to errors. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Is the a better way? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Assuming that you actually have more than one user account and that you &lt;br /&gt;are concerned with the set of Personnel and not a single employee, &lt;br /&gt;let's use names that follow ISO-11179 rules.  You might be able to do &lt;br /&gt;this: &lt;br /&gt;&lt;br /&gt;DELETE FROM UserAccounts &lt;br /&gt; WHERE EXISTS &lt;br /&gt;      (SELECT * &lt;br /&gt;         FROM Personnel AS P &lt;br /&gt;        WHERE UserAccounts.person_id = P.person_id &lt;br /&gt;          AND P.employer_id = 66); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This can use indexes instead of being forced to materialize a JOIN &lt;br /&gt;result. You can drop the  WITH (NOLOCK) options since a statement is &lt;br /&gt;treated as a transaction.  Think about predicates and not about &lt;br /&gt;creating table.  That is how we did data processing with scratch tapes &lt;br /&gt;in the old days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791403740470981?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791403740470981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791403740470981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791403740470981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791403740470981'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/delete-with-inner-join.html' title='Delete with inner join'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791391288057322</id><published>2006-09-10T14:44:00.000-04:00</published><updated>2006-09-10T14:45:17.816-04:00</updated><title type='text'>Please explain Ternary relationship to me.</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;There is a very basic, simple ternary relationship.&lt;br /&gt;&lt;a href="http://explorer.x-y.net/data/f1.gif"&gt;http://explorer.x-y.net/data/f1.gif&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The question is to get choose a possible combination of each A,B,C&lt;br /&gt;entity count, and the number of triples in R.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I thought that since there should be 1 B for each A, max number of A-&gt;B&lt;br /&gt;is the number of entities in A. And since there is a C for each A-&gt;B,&lt;br /&gt;(A-&gt;B)-&gt;C is the number of A-&gt;B&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But I was wrong. But the correct answer is not explained, and I&lt;br /&gt;couldn't find any information about these kind of problem on the text&lt;br /&gt;book. The text book just gives very simple concept explanation nothing&lt;br /&gt;more. Would you please tell me more about ternary relationship and how&lt;br /&gt;to count the number of triples? Thank you in advance.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I couldn't find any information about these kind of problem on the text book. The text book just gives very simple concept explanation nothing more. Would you please tell me more about ternary relationship and how to count the number of triples? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You cannot break it into binary relations like you are trying to do. &lt;br /&gt;&lt;br /&gt;Fifth Normal Form (5NF), also called the Join-Projection Normal Form or &lt;br /&gt;the Projection-Join Normal Form, is based on the idea of a lossless &lt;br /&gt;JOIN or the lack of a join-projection anomaly.  This problem occurs &lt;br /&gt;when you have an n-way relationship, where n &gt; 2.  A quick check for &lt;br /&gt;5NF is to see if the table is in 3NF and all the candidate keys are &lt;br /&gt;single columns. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As an example of the problems solved by 5NF, consider a table of house &lt;br /&gt;notes that records the buyer, the seller, and the lender: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HouseNotes &lt;br /&gt;buyer     seller    lender &lt;br /&gt;================================== &lt;br /&gt;'Smith'   'Jones'     'National Bank' &lt;br /&gt;'Smith'   'Wilson'    'Home Bank' &lt;br /&gt;'Nelson'  'Jones'     'Home Bank' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This table is a three-way relationship, but because many CASE tools &lt;br /&gt;allow only binary relationships it might have to be expressed in an E-R &lt;br /&gt;diagram as three binary relationships, which would generate CREATE &lt;br /&gt;TABLE statements leading to these tables: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;BuyerLender &lt;br /&gt;buyer     lender &lt;br /&gt;============================= &lt;br /&gt;'Smith'      'National Bank' &lt;br /&gt;'Smith'      'Home Bank' &lt;br /&gt;'Nelson'     'Home Bank' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SellerLender &lt;br /&gt;seller    lender &lt;br /&gt;======================= &lt;br /&gt;'Jones'     'National Bank' &lt;br /&gt;'Wilson'    'Home Bank' &lt;br /&gt;'Jones'     'Home Bank' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;BuyerSeller &lt;br /&gt;buyer   seller &lt;br /&gt;================ &lt;br /&gt;'Smith'   'Jones' &lt;br /&gt;'Smith'   'Wilson' &lt;br /&gt;'Nelson'  'Jones' &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The trouble is that when you try to assemble the original information &lt;br /&gt;by joining pairs of these three tables together, thus: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT BS.buyer, SL.seller, BL.lender &lt;br /&gt;  FROM BuyerLender AS BL, &lt;br /&gt;       SellerLender AS SL, &lt;br /&gt;       BuyerSeller AS BS &lt;br /&gt; WHERE BL.buyer = BS.buyer &lt;br /&gt;   AND BL.lender = SL.lender &lt;br /&gt;   AND SL.seller = BS.seller; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;you will recreate all the valid rows in the original table, such as &lt;br /&gt;('Smith', 'Jones', 'National Bank'), but there will also be false rows, &lt;br /&gt;such as ('Smith', 'Jones', 'Home Bank'), which were not part of the &lt;br /&gt;original table.  This is called a join-projection anomaly. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There are also strong JPNF and overstrong JPNF, which make use of JOIN &lt;br /&gt;dependencies (JD for short).  Unfortunately, there is no systematic way &lt;br /&gt;to find a JPNF or 4NF schema, because the problem is known to be NP &lt;br /&gt;complete.  This is a mathematical term that means as the number of &lt;br /&gt;elements in a problem increase, the effort to solve it increases so &lt;br /&gt;fast and requires so many resources that you cannot find a general &lt;br /&gt;answer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791391288057322?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791391288057322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791391288057322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791391288057322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791391288057322'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/please-explain-ternary-relationship-to.html' title='Please explain Ternary relationship to me.'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791312623382617</id><published>2006-09-10T14:31:00.000-04:00</published><updated>2006-09-10T14:32:06.376-04:00</updated><title type='text'>working with gaps in date series</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I've seen some pretty creative SQL statements that locate &lt;br /&gt;first/last/missing elements in a series but I haven't been able to &lt;br /&gt;adapt any of them to work speedily with my data set. &lt;br /&gt;&lt;br /&gt;Here's the problem: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We have a table of services for our clients (about 2 million rows). &lt;br /&gt;The rows are simply the client's ID and the date of service.  Rows may &lt;br /&gt;dupe as clients may have more than one service per date. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We need to be able to define a case start and end date for each client &lt;br /&gt;ID.  The end date is defined as the last service date with no further &lt;br /&gt;activity within some number (usually 180) of days.  Furthermore, I'd &lt;br /&gt;need to enumerate the cases per client. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So using the example below, I'd be looking for results such as: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Client  Start       End          Case &lt;br /&gt;55577   2/01/2004   5/11/2004    1 &lt;br /&gt;55577   1/09/2005   1/09/2005    2 &lt;br /&gt;55577   3/04/2006   OPEN         3 &lt;br /&gt;72395   4/04/2006   OPEN         1 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In these cases, the OPEN dates indicate that there has not been a 180 &lt;br /&gt;day period of inactivity since the most recent date. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I currently do this in VB, looping through the ServList dataset and &lt;br /&gt;populating a CaseList recordset.  It takes about 30mins to run the job. &lt;br /&gt; However, I'd prefer doing it all in a stored procedure and I'd prefer &lt;br /&gt;to do it without use of cursors.  Possible? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks for any help/thoughts, &lt;br /&gt;Steve &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE #ServList ( &lt;br /&gt;  ClientID int &lt;br /&gt;, ServDate smalldatetime) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '2/01/2004') &lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '2/01/2004') &lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '5/11/2004') &lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '1/09/2005') &lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '3/04/2006') &lt;br /&gt;INSERT INTO #Servlist VALUES (55577, '5/17/2006') &lt;br /&gt;INSERT INTO #Servlist VALUES (72395, '4/04/2006') &lt;br /&gt;INSERT INTO #Servlist VALUES (72395, '4/05/2006') &lt;br /&gt;INSERT INTO #Servlist VALUES (72395, '4/06/2006') &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  We have a table of services for our clients (about 2 million rows). The rows are simply the client's ID and the date of service.  Rows may dupe as clients may have more than one service per date.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Clear specs, thank you!!  But weak DDL and you do not seem to know that &lt;br /&gt;SQL uses ISO-8601 date formats, like all other ISO standards do, in the &lt;br /&gt;sample data.  Here is my guess at the real DDL: &lt;br /&gt;&lt;br /&gt;CREATE TABLE ServiceTickets &lt;br /&gt;(client_id CHAR(5) NOT NULL &lt;br /&gt;   REFERENCES Clients(client_id) &lt;br /&gt;   ON UPDATE CASCADE &lt;br /&gt;   ON DELETE CASCADE, &lt;br /&gt; service_code CHAR(5) NOT NULL &lt;br /&gt;   REFERENCES Services(service_code) &lt;br /&gt;   ON UPDATE CASCADE, &lt;br /&gt; service_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, &lt;br /&gt; service_period INTEGER DEFAULT 0 NOT NULL, &lt;br /&gt;  PRIMARY KEY (client_id, service_code, service_date)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; We need to be able to define a case start and end date for each client ID.  The end date is defined as the last service date with no further activity within some number (usually 180) of days.  Furthermore, I'd need to enumerate the cases per client. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Change the way you think for a minute.  Data and declarations, not &lt;br /&gt;procedures and computations.  SQL, not VB. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I currently do this in VB, looping through the ServList dataset and populating a CaseList recordset.  It takes about 30 mins to run the job. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Build a table with (n) years of these reporting periods of 180 (or &lt;br /&gt;whatever) days.  A spreadsheet is great for this kind of thing. &lt;br /&gt;&lt;br /&gt;CREATE TABLE CasePeriods -- needs better name &lt;br /&gt;(service_period INTEGER NOT NULL PRIMARY KEY &lt;br /&gt;  CHECK (case_period_nbr &gt; 0), &lt;br /&gt; start_date DATETIME NOT NULL, &lt;br /&gt; end_date DATETIME NOT NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now we can find the first service_period that a client has. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT T.client_id, MIN(C.service_period) &lt;br /&gt;  FROM ServiceTickets AS T, CasePeriods AS C &lt;br /&gt; WHERE T.service_date BETWEEN  C.start_date AND C.end_date &lt;br /&gt;   AND end_date &lt; CURRENT_TIMESTAMP -- completed periods only &lt;br /&gt;   AND service_period = 0 -- unassigned periods &lt;br /&gt;   AND ?? &lt;br /&gt;GROUP BY T.client_id &lt;br /&gt;HAVING COUNT(*) &gt; 0; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have a question about the rules.  If the guy comes in on day 1, then &lt;br /&gt;comes back on day 180 and 181, are we in the same case or not?  If the &lt;br /&gt;guy comes in on day 1, then comes back on day 180 and 182, are we in &lt;br /&gt;the same case or not? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Test this, then use it in an UPDATE statement to put a value in the &lt;br /&gt;service_period column for those rows that are within your (n) day &lt;br /&gt;range.  We could hide this in a VIEW, but it looks complex enough to &lt;br /&gt;materialize the service_period values. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; In these cases, the OPEN dates indicate that there has not been a 180 day period of inactivity since the most recent date. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ther ain't no such date as "Open"; this is why I used a zero reporting &lt;br /&gt;period for the things in process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791312623382617?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791312623382617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791312623382617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791312623382617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791312623382617'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/working-with-gaps-in-date-series.html' title='working with gaps in date series'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791300640643136</id><published>2006-09-10T14:28:00.000-04:00</published><updated>2006-09-10T14:30:06.583-04:00</updated><title type='text'>An interesting Lastname, Firstname, Middlename challenge</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I'm sure you all have seen situations where a field has a combined name &lt;br /&gt;in the format of "Lastname, Firstname Middlename" and I've seen &lt;br /&gt;examples of parsing that type of field.  But what happens when the data &lt;br /&gt;within this type of field is inconsistent?  Here are some examples &lt;br /&gt;&lt;br /&gt;Apple, John A. &lt;br /&gt;Berry John B. &lt;br /&gt;CherryJohn C &lt;br /&gt;Donald John D &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How does one parse the data when the data isn't consistent? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; How does one parse the data when the data isn't consistent? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I get a mailing package and save myself a lot of problems -- why &lt;br /&gt;re-invent the wheel? &lt;br /&gt;&lt;br /&gt;Group 1 Software ,  Melissa Data Corporation  and SAA are such &lt;br /&gt;companies.  They can scrub mailing lists MUCH better than you can -- &lt;br /&gt;unless you want to make a major project of it for a few years.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791300640643136?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791300640643136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791300640643136' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791300640643136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791300640643136'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/interesting-lastname-firstname.html' title='An interesting Lastname, Firstname, Middlename challenge'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791288836940599</id><published>2006-09-10T14:27:00.000-04:00</published><updated>2006-09-10T14:28:19.676-04:00</updated><title type='text'>Change Query Table</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a series of tables in the database that hold orders for of the &lt;br /&gt;months &lt;br /&gt;i.e. &lt;br /&gt;Tbl: June06 &lt;br /&gt;OrderNo,  Amount &lt;br /&gt;0001         100 &lt;br /&gt;102           150 &lt;br /&gt;&lt;br /&gt;Tbl: July06 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What I want to do is, when a user passes in the month say July06, I &lt;br /&gt;should query from table call June06. &lt;br /&gt;Instead of putting the entire query in a string, is there a way to &lt;br /&gt;switch the table names? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My query is long and I have tables for couple years. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  I have a series of tables in the database that hold orders for of the months &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"series of tables"???  No such animal in RDBMS.  A table models a set &lt;br /&gt;of entities or relationship of the same -- the whole damn set, not &lt;br /&gt;parts of it.  This is just basic math and elementary school set theory, &lt;br /&gt;not advanced stuff. &lt;br /&gt;&lt;br /&gt;This total screw up has a name -- Attribute Splitting.  You take the &lt;br /&gt;values of an attribute and make them into columns or tables in the &lt;br /&gt;schema.  Do you also have separate table for employees based on gender &lt;br /&gt;or religion?  Same stupid error! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt;  What I want to do is, when a user passes in the month say July06, I should query from table call June06.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is one of the MANNNNNY reasons this is screwed up, non-relational &lt;br /&gt;design.  You are mimicing a 1950's magentic tape system!  LITERALLY!! &lt;br /&gt;The tape labels had "yyddd" so you could keep track of them. &lt;br /&gt;&lt;br /&gt;Put everything in one table, create a reporting period table: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE ReportPeriods &lt;br /&gt;(period_name CHAR(10) NOT NULL PRIMARY KEY, &lt;br /&gt; start_date DATE NOT NULL, &lt;br /&gt; end_date DATE NOT NULL, &lt;br /&gt;  etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Use a BETWEEN predicate JOIN to classify your data. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also, name the periods in alphabetic order for sorting.  That means &lt;br /&gt;"2006-06" and not "Jun06"; this is a basic programming trick  and not &lt;br /&gt;just SQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791288836940599?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791288836940599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791288836940599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791288836940599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791288836940599'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/change-query-table.html' title='Change Query Table'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791267401295600</id><published>2006-09-10T14:22:00.000-04:00</published><updated>2006-09-10T14:24:35.750-04:00</updated><title type='text'>Best way to insert data into tables without primary keys</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am working on a SQL Server database in which there are no primary &lt;br /&gt;keys set on the tables.  I can tell what they are using for a key.  It &lt;br /&gt;is usually named ID, has a data type of int and does not allow nulls. &lt;br /&gt;However, since it is not set as a primary key you can create a &lt;br /&gt;duplicate key. &lt;br /&gt;&lt;br /&gt;This whole thing was created by someone who is long gone.  I don't &lt;br /&gt;know how long I will be here and I don't want to break anything.  I &lt;br /&gt;just want to work with things the way they are. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So if I want to insert a new record, and I want the key, which  is &lt;br /&gt;named ID, to be the next number in the sequence, is there something  I &lt;br /&gt;can do in an insert sql statement to do this? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt;  I am working on a SQL Server database in which there are no primary keys set on the tables. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;By definition, it is not a table at all, but a simple file written with &lt;br /&gt;SQL .. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I can tell what they are using for a key.  It is usually named ID, has a data type of int and does not allow nulls.&lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ah yes, the Magical, Universal "id" that God put on all things in &lt;br /&gt;creation.  To hell with ISO-11179 and metadata, to hell with Aristotle &lt;br /&gt;and the law of identity! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; However, since it is not set as a primary key you can create a duplicate key. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Duplicate key is an oxymoron &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; This whole thing was created by someone who is long gone.  I don't know how long I will be here and I don't want to break anything.  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A better question; how long can an enterprise with a DB like this &lt;br /&gt;survive?  I'd be updating the resume and stealing office supplies. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; &gt; So if I want to insert a new record [sic], and I want the key, which  is named ID, to be the next number in the sequence, is there something  I can do in an insert statement to do this?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Rows are not anything like records; the failure of the first guy to &lt;br /&gt;understand this is why he mimiced a magnetic tape file system's record &lt;br /&gt;numbers instad of providing a relational key. &lt;br /&gt;&lt;br /&gt;The stinking dirty kludge is to use  "SELECT MAX(id)+1 FROM Foobar" in &lt;br /&gt;the INSERT INTO statements. Oh, you also need to check for dups and add &lt;br /&gt;a uniqueness constraint (mop the floor and fix the leak). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The right answer is to re-design this system properly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791267401295600?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791267401295600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791267401295600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791267401295600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791267401295600'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/best-way-to-insert-data-into-tables.html' title='Best way to insert data into tables without primary keys'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791251665598007</id><published>2006-09-10T14:20:00.000-04:00</published><updated>2006-09-10T14:21:56.803-04:00</updated><title type='text'>Update Query in SQL 2005 with inner join</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have the following update query &lt;br /&gt;&lt;br /&gt;UPDATE    Employee &lt;br /&gt;SET              Deactivated = 1 &lt;br /&gt;FROM         Employee AS Employee_1 INNER JOIN &lt;br /&gt;                      Assignment ON Employee_1.SSN = Assignment.SSN CROSS &lt;br /&gt;JOIN &lt;br /&gt;                      Employee &lt;br /&gt;WHERE     (Assignment.SCHOOLID = '0') AND (Assignment.TERM IS NULL) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and it updates, but the problem is it is updating the complete table and not &lt;br /&gt;filtering with the where statement. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Any ideas? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Do you really have just one Employee, as you said with your data &lt;br /&gt;element name?  Are you really using assembly language bit flags in SQL? &lt;br /&gt; SQL programmers do not set flags; they use predicates and VIEWs to &lt;br /&gt;find the state of their data.  Programmers who work with punch cards &lt;br /&gt;set flags. &lt;br /&gt;&lt;br /&gt;SQL programmers also know not to use the proprietary UPDATE.. FROM.. &lt;br /&gt;syntax.  Here is what I think you were trying to do in Standard, &lt;br /&gt;portable, predictable SQL.  I also cleaned up your data element names &lt;br /&gt;to look more like ISO-11179: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE Personnel &lt;br /&gt;   SET deactivated_flag  = 1 &lt;br /&gt;WHERE EXISTS &lt;br /&gt;      (SELECT * &lt;br /&gt;         FROM  Personnel AS P,  Assignments AS A &lt;br /&gt;       WHERE P.ssn = Personnel.ssn &lt;br /&gt;          AND A.ssn = Personnel.ssn &lt;br /&gt;          AND A.school_id = '0' &lt;br /&gt;          AND A.school_term IS NULL); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;One of the MANY reasons that we do not use bit flags or even have &lt;br /&gt;Booleans in SQL is that   when someone modifes Assignments.school_term &lt;br /&gt;your deactivated_flag is wrong.  Now you need procedural code in a &lt;br /&gt;trigger to fix this, or to run a stored procedure whenever there is any &lt;br /&gt;doubt. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you use a VIEW and quit thinking like a punch card programmer, then &lt;br /&gt;the data is *always* correct: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW ActivePersonnel (..) &lt;br /&gt;AS &lt;br /&gt;SELECT .. &lt;br /&gt;  FROM Personnel AS P &lt;br /&gt;WHERE WHERE EXISTS &lt;br /&gt;      (SELECT * &lt;br /&gt;         FROM  Assignments AS A &lt;br /&gt;       WHERE A.ssn = P.ssn &lt;br /&gt;          AND A.school_id = '0' &lt;br /&gt;          AND A.school_term IS NULL);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791251665598007?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791251665598007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791251665598007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791251665598007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791251665598007'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/update-query-in-sql-2005-with-inner.html' title='Update Query in SQL 2005 with inner join'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791242865180639</id><published>2006-09-10T14:17:00.000-04:00</published><updated>2006-09-10T14:20:30.363-04:00</updated><title type='text'>Identity column as a foreign key - help needed in logic</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have these tables as shown below. Say I want to duplicate a condition &lt;br /&gt;group with ID = 10. Notice that there are identity columns in the Conditions &lt;br /&gt;and Values tables. I can use a INSERT INTO ... SELECT FROM to insert new &lt;br /&gt;rows into the ConditionGroups table. But when I get to Conditions and Values &lt;br /&gt;subsequently I will need to get the generated identity value first before I &lt;br /&gt;insert values. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What's the best way to do this? I want to do this in the database itself. &lt;br /&gt;Are cursors avoidable? &lt;br /&gt;&lt;br /&gt;-------------- &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[ConditionGroups] ( &lt;br /&gt; [ID] [int] IDENTITY (1, 1) NOT NULL , &lt;br /&gt; [Name] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[Conditions] ( &lt;br /&gt; [ID] [int] IDENTITY (1, 1) NOT NULL , &lt;br /&gt; [ConditionGroupID] [int] NULL , &lt;br /&gt; [Lhs] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , &lt;br /&gt; [Operator] [char] (3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE [dbo].[Values] ( &lt;br /&gt; [ID] [int] NOT NULL , &lt;br /&gt; [ConditionID] [int] NOT NULL , &lt;br /&gt; [RhsValue] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL &lt;br /&gt;) ON [PRIMARY] &lt;br /&gt;GO &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; Can it be better modeled? &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL is for data and **not** for rules.  You ought to be using Prolog or &lt;br /&gt;LISP.  You are trying to drive nails with a pumpkin.  Having said all &lt;br /&gt;that, people will call me mean if I do not give you this kludge: &lt;br /&gt;&lt;br /&gt;I think what you want is the ability to load tables with criteria and &lt;br /&gt;not have to use dynamic SQL: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;skill = Java AND (skill = Perl OR skill = PHP) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;becomes the disjunctive canonical form: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(Java AND Perl) OR (Java AND PHP) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; which we load into this table: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Query &lt;br /&gt;(and_grp INTEGER NOT NULL, &lt;br /&gt; skill CHAR(4) NOT NULL, &lt;br /&gt; PRIMARY KEY (and_grp, skill)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Query VALUES (1, 'Java'); &lt;br /&gt;INSERT INTO Query VALUES (1, 'Perl'); &lt;br /&gt;INSERT INTO Query VALUES (2, 'Java'); &lt;br /&gt;INSERT INTO Query VALUES (2, 'PHP'); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Assume we have a table of job candidates: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Candidates &lt;br /&gt;(candidate_name CHAR(15) NOT NULL, &lt;br /&gt; skill CHAR(4) NOT NULL, &lt;br /&gt; PRIMARY KEY (candidate_name, skill)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Candidates VALUES ('John', 'Java'); --winner &lt;br /&gt;INSERT INTO Candidates VALUES ('John', 'Perl'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Mary', 'Java'); --winner &lt;br /&gt;INSERT INTO Candidates VALUES ('Mary', 'PHP'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Larry', 'Perl'); --winner &lt;br /&gt;INSERT INTO Candidates VALUES ('Larry', 'PHP'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Moe', 'Perl'); --winner &lt;br /&gt;INSERT INTO Candidates VALUES ('Moe', 'PHP'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Moe', 'Java'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Celko', 'Java'); -- loser &lt;br /&gt;INSERT INTO Candidates VALUES ('Celko', 'Algol'); &lt;br /&gt;INSERT INTO Candidates VALUES ('Smith', 'APL');  -- loser &lt;br /&gt;INSERT INTO Candidates VALUES ('Smith', 'Algol'); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The query is simple now: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT DISTINCT C1.candidate_name &lt;br /&gt;  FROM Candidates AS C1, Query AS Q1 &lt;br /&gt; WHERE C1.skill = Q1.skill &lt;br /&gt; GROUP BY Q1.and_grp, C1.candidate_name &lt;br /&gt;HAVING COUNT(C1.skill) &lt;br /&gt;       = (SELECT COUNT(*) &lt;br /&gt;            FROM Query AS Q2 &lt;br /&gt;           WHERE Q1.and_grp = Q2.and_grp); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can retain the COUNT() information to rank candidates.  For example &lt;br /&gt;Moe meets both qualifications, while other candidates meet only one of &lt;br /&gt;the two. You can Google "canonical disjunctive form" for more details. &lt;br /&gt;This is a form of relational division.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791242865180639?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791242865180639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791242865180639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791242865180639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791242865180639'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/identity-column-as-foreign-key-help.html' title='Identity column as a foreign key - help needed in logic'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791223717178088</id><published>2006-09-10T14:15:00.000-04:00</published><updated>2006-09-10T14:17:17.240-04:00</updated><title type='text'>Query Problem</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I have an orders table and an order_items table. Simply, they look like &lt;br /&gt;this: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Orders: &lt;br /&gt;ID | Status &lt;br /&gt;------- &lt;br /&gt; 0 | New &lt;br /&gt; 1 | InProgress &lt;br /&gt; 2 | InProgress &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Order_Items: &lt;br /&gt;ID | Ord_ID | Supplier | Status &lt;br /&gt;------------- &lt;br /&gt; 0 |   0    |   Fred   | New &lt;br /&gt; 1 |   1    |   Fred   | New &lt;br /&gt; 2 |   1    |   Fred   | Complete &lt;br /&gt; 3 |   2    |   Fred   | New &lt;br /&gt; 4 |   2    |   Joe    | Complete &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When Joe wants to view his 'Complete' Orders, he should see order 2, &lt;br /&gt;because all his items for order 2 are complete (even though its &lt;br /&gt;orderstatus is inprogress) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When Fred wants to view his new orders, he should see order 0 and 2 &lt;br /&gt;(because all his items for 2 are new), and order 1 should be seen as &lt;br /&gt;inprogress. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How can i write a query which given a supplier and status (either new, &lt;br /&gt;inprogress or complete) will return all the relevant orders? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;&lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;your schema are. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Look at that Orders table -- vague "id" that might or might not be a &lt;br /&gt;key (you are not using IDENTITY for order numbers, are you!!??); vague &lt;br /&gt;"status" attribute (what kind of status??).  Cann't this be done in a &lt;br /&gt;view off of the OrderItems table instead of mimicing a file?  Look up &lt;br /&gt;how to name a data element. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is my guess and corrections to your "pseudo-code" non-table &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Order_Items &lt;br /&gt;(order_nbr INTEGER NOT NULL &lt;br /&gt;   CHECK (&lt;&lt; validation rule here&gt;&gt;), &lt;br /&gt; item_nbr INTEGER NOT NULL &lt;br /&gt;   CHECK (item_nbr &gt; 0), &lt;br /&gt; supplier_name CHAR(10) NOT NULL &lt;br /&gt;   REFERENCES Suppliers (supplier_name) &lt;br /&gt;   ON UPDATE CASCADE, &lt;br /&gt; item_status CHAR(1) DEFAULT 'N' NOT NULL &lt;br /&gt;   CHECK (item_status IN ('N', 'C'), -- new, completed &lt;br /&gt; PRIMARY KEY (order_nbr, item_nbr)); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notice the use of a relational key, instead of mimicing a tape file &lt;br /&gt;record number? The use of IDENTITY for items in a bill of materials or &lt;br /&gt;order problem screw up things. Use an item number within the order &lt;br /&gt;number. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT INTO Order_Items VALUES (0, 1, 'Fred', 'N'); &lt;br /&gt;INSERT INTO Order_Items VALUES (1, 1, 'Fred', 'N'); &lt;br /&gt;INSERT INTO Order_Items VALUES (1, 2, 'Fred', 'C'); &lt;br /&gt;INSERT INTO Order_Items VALUES (2, 1, 'Fred', 'N'); &lt;br /&gt;INSERT INTO Order_Items VALUES (2, 2, 'Joe', 'C'); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is, in Order #2, Fred supplied item #1 and Joe supplied item #2. &lt;br /&gt;Lot easier to track things with a proper design. Now throw out your &lt;br /&gt;redundant table: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE VIEW OrderStatus (order_nbr, supplier, order_status) &lt;br /&gt;AS &lt;br /&gt;SELECT order_nbr, supplier, &lt;br /&gt;       CASE WHEN MIN(item_status) = 'New' &lt;br /&gt;            THEN 'New' &lt;br /&gt;            WHEN MAX(item_status) = 'Complete' &lt;br /&gt;            THEN 'Complete' &lt;br /&gt;            ELSE 'In Progress' END; &lt;br /&gt;  FROM Order_Items &lt;br /&gt; GROUP BY order_nbr, supplier; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The VIEW is always current and you do not have to keep writing to disk &lt;br /&gt;to mimic a physical file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791223717178088?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791223717178088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791223717178088' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791223717178088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791223717178088'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/query-problem.html' title='Query Problem'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115791199535640126</id><published>2006-09-10T14:12:00.000-04:00</published><updated>2006-09-10T14:13:18.066-04:00</updated><title type='text'>Why do I get different results with this?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;This is taken from a large but not very complex SQL statement. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;,SUM (CASE ELUBECOUPONS.TICKETID  WHEN  NULL THEN 0 ELSE        1 END)   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;when I execute the statement with the one above the answer is 0 rows. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If I change that statement to: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;,SUM (CASE      WHEN ELUBECOUPONS.TICKETID  IS NULL     THEN 0 ELSE     1 END) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the answer is 624,510 rows &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Same database, I only changed this one result column. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I clearly don't understand something about the case statement.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;What is the basic rule about NULLs?  They cannot be compared to &lt;br /&gt;anything, even eaqch other!  You mean to use the other form of CASE &lt;br /&gt;expression: &lt;br /&gt;&lt;br /&gt;SUM (CASE WHEN ElubeCoupons.ticket_nbr  IS  NULL THEN 0 ELSE 1 END) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since SUM() drops out NULLs, you could use this with numeric ticket &lt;br /&gt;numbers. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SUM (SIGN (ElubeCoupons.ticket_nbr)) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Little data modeling thing; a "_nbr" implies a sequence or other &lt;br /&gt;generating rule for the numeric or pseudo-numeric value.  "_id" just &lt;br /&gt;says that the value is unique.  That is why we talk about ticket &lt;br /&gt;numbers and not ticket identifiers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115791199535640126?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115791199535640126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115791199535640126' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791199535640126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115791199535640126'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/why-do-i-get-different-results-with.html' title='Why do I get different results with this?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115782417012626147</id><published>2006-09-09T13:48:00.000-04:00</published><updated>2006-09-09T13:49:30.213-04:00</updated><title type='text'>Graph Representations</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt; have a problem that's twisting my mind up. The summary of the problem is &lt;br /&gt;that I have table of organizations, each of which can function in one of two &lt;br /&gt;roles at any given time - call them Role A and role B. These organizations &lt;br /&gt;will have relationships between them (I imagine it programatically as a &lt;br /&gt;directed graph or linked list)...possibly to an infinite degree. For &lt;br /&gt;example - representing the organizations by numerals (maybe their primary &lt;br /&gt;key in the table) and the roles as defined above - we might have the &lt;br /&gt;following: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(org 1 in role A -&gt; org 2 in role B -&gt; org 3 in role A...) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1A-&gt;2B-&gt;3A-&gt;4B-&gt;5A &lt;br /&gt;                             |-&gt;6A &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(org 2 in role A -&gt; org 3 in role B...) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2A-&gt;3B-&gt;5A &lt;br /&gt;            |-&gt;2B-&gt;4A &lt;br /&gt;                    |-&gt;6A &lt;br /&gt;                    |-&gt;7A &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see, each organization will be a "root" node, but then the path &lt;br /&gt;can take nearly progression to and from the other organizations, having an &lt;br /&gt;infinite number of traditional "edges" in a graph. The graph would &lt;br /&gt;ultimately end at one or more "leaf" nodes (as represented above). This &lt;br /&gt;graph represents the relationships between the associated organizations. &lt;br /&gt;There is no mutual exclusion between the paths: in other words, multiple &lt;br /&gt;organizations may have a relationship with 5A (org 5 in role A) - as shown &lt;br /&gt;above. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How in the world do I represent these relationships in a database structure? &lt;br /&gt;Please help. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;Try a modifed nested sets model.  Nodes have a compound key: &lt;br /&gt;&lt;br /&gt;CREATE TABLE Nodes &lt;br /&gt;(node_id INTEGER NOT NULL &lt;br /&gt;  CHECK(node_id &gt; 0), &lt;br /&gt; node_type CHAR(1) NOT NULL &lt;br /&gt;  CHECK(node_type IN ('A', 'B'), &lt;br /&gt; PRIMARY KEY (node_id, node_type), &lt;br /&gt; etc.); &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The forest of various arrangements of nodes has to identify each tree &lt;br /&gt;in that forest: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE Forest &lt;br /&gt;(tree_id INTEGER NOT NULL, &lt;br /&gt; node_id INTEGER NOT NULL, &lt;br /&gt; node_type CHAR(1) NOT NULL, &lt;br /&gt;  REFERENCES Nodes (node_id, node_type) &lt;br /&gt;    ON UPDATE CASCADE &lt;br /&gt;    ON DELETE CASCADE, &lt;br /&gt; PRIMARY KEY (tree_id, node_id) &lt;br /&gt; lft INTEGER NOT NULL, &lt;br /&gt; rgt INTEGER NOT NULL, &lt;br /&gt; UNIQUE (tree_id, lft), &lt;br /&gt;  etc. &lt;br /&gt;);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115782417012626147?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115782417012626147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115782417012626147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782417012626147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782417012626147'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/graph-representations.html' title='Graph Representations'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115782367060037997</id><published>2006-09-09T13:31:00.000-04:00</published><updated>2006-09-09T13:41:10.746-04:00</updated><title type='text'>hierarchical query 2005</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I am working with visual studio 2005 and sql server 2005 workgroup edition.&lt;br /&gt;I have three tables where each row has an ID and a PID.&lt;br /&gt;What I want to do is create either a hierarchical query to fill a data set&lt;br /&gt;or create the dataset itself as an hierarchial dataset.&lt;br /&gt;Is this possible with the tools I`m using and if so, how?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; I have three tables where each row has an ID and a PID. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please post DDL, so that people do not have to guess what the keys, &lt;br /&gt;constraints, Declarative Referential Integrity, data types, etc. in &lt;br /&gt;your schema are. Sample data is also a good idea, along with clear &lt;br /&gt;specifications.  It is very hard to debug code when you do not let us &lt;br /&gt;see it. &lt;br /&gt;&lt;br /&gt;Also, why did you think that "id" and "pid" have any meaning to other &lt;br /&gt;people?  "id" is a postfix in ISO-11179 which is too vague to stand by &lt;br /&gt;itself -- it begs the question "identiifer of what?" by its very &lt;br /&gt;nature. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; What I want to do is create either a hierarchical query to fill a data set or create the dataset itself as an hierarchial dataset. &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What is a " hierarchical query"?  That term was never used in SQL while &lt;br /&gt;I was on the Committee.  You might want to get a copy of &lt;a href="http://www.amazon.com/exec/obidos/ASIN/1558609202/sql08-20/102-5735017-0910517?%5Fencoding=UTF8&amp;camp=1789&amp;link%5Fcode=xm2"&gt;TREES &amp; &lt;br /&gt;HIERARCHIES IN SQL &lt;/a&gt;for *several* different ways to model a hierarchy or &lt;br /&gt;a tree.  But first, you might want to learn some basics. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;I`m sorry for being a bit unclear.&lt;br /&gt;the tables are:&lt;br /&gt;&lt;br /&gt;category:&lt;br /&gt;cat_id int (PK)&lt;br /&gt;cat_name nvarchar&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;subcategory:&lt;br /&gt;subcat_id int (PK)&lt;br /&gt;parent_id int&lt;br /&gt;subcat_name nvarchar&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;items:&lt;br /&gt;item_id int (PK)&lt;br /&gt;parent_id int (can be category or sub-category)&lt;br /&gt;item_name nvarchar&lt;br /&gt;item_desc nvarchar&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I want to display the data (in some control, tree or other, I`m open to&lt;br /&gt;suggestions)&lt;br /&gt;so that each category contains the items and sub-categories where the parent&lt;br /&gt;id is the id of the category and so on going into the hierarchy.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&gt;&gt; I`m sorry for being a bit unclear. &lt;&lt;&gt;&gt; );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Google "nested sets model" explain the following&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CREATE TABLE FishTaxonomy&lt;br /&gt;(fish_id INTEGER NOT NULL&lt;br /&gt;REFERENCES Fishes (fish_id)&lt;br /&gt;ON UPDATE CASCADE,&lt;br /&gt;lft INTEGER NOT NULL UNIQUE,&lt;br /&gt;rgt INTEGER NOT NULL UNIQUE,&lt;br /&gt;CHECK(lft &lt; rgt) );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A given fish_id and all their superiorss, no matter how deep the tree.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT F2.*&lt;br /&gt;FROM FishTaxonomy AS F1, FishTaxonomy AS F2&lt;br /&gt;WHERE F1.lft BETWEEN F2.lft AND F2.rgt&lt;br /&gt;AND F1.fish_id = :my_fish_id;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. The fish_id and all their subordinates. There is a nice symmetry&lt;br /&gt;here.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SELECT F1.*&lt;br /&gt;FROM FishTaxonomy AS F1, FishTaxonomy AS F2&lt;br /&gt;WHERE F1.lft BETWEEN F2.lft AND F2.rgt&lt;br /&gt;AND F2.fish_id = :my_fish_id;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115782367060037997?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115782367060037997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115782367060037997' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782367060037997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782367060037997'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/hierarchical-query-2005.html' title='hierarchical query 2005'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25819301.post-115782277994522221</id><published>2006-09-09T13:25:00.000-04:00</published><updated>2006-09-09T13:26:20.096-04:00</updated><title type='text'>Passing parameter into SP for permissions?</title><content type='html'>&lt;strong&gt;SQL Apprentice Question&lt;/strong&gt;&lt;br /&gt;How can I pass a user name into a stored procedure I've created that &lt;br /&gt;assigns certain table and SP permissions?  The EXECUTE doesn't seem to &lt;br /&gt;allow variables when permissions are involved.  It wants literals, i.e. &lt;br /&gt;'John' instead of @username. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Celko Answers&lt;/strong&gt;&lt;br /&gt;&gt;&gt; How can I pass a user name into a stored procedure I've created that assigns certain table and SP permissions?  &lt;&lt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can probably do it with dynamic SQL, but why not use the DCL and &lt;br /&gt;keep your system secure? &lt;br /&gt;&lt;br /&gt;You do have a security officer who creates and monitors the user &lt;br /&gt;accounts, don't you?  Or do you really do it at the application level &lt;br /&gt;on the fly?  If so, have you told the security officer and the auditors &lt;br /&gt;about this "feature" to subvert authority?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25819301-115782277994522221?l=joecelkothesqlapprentice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://joecelkothesqlapprentice.blogspot.com/feeds/115782277994522221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=25819301&amp;postID=115782277994522221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782277994522221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25819301/posts/default/115782277994522221'/><link rel='alternate' type='text/html' href='http://joecelkothesqlapprentice.blogspot.com/2006/09/passing-parameter-into-sp-for.html' title='Passing parameter into SP for permissions?'/><author><name>SQL</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
