Showing posts with label SQL Statements. Show all posts
Showing posts with label SQL Statements. Show all posts

Thursday, March 15, 2012

Database Development - Data Omission 1


ALTER PROCEDURE dbo.usp_blg_vkj_0000002 AS
BEGIN

/* Here is an example of omitting data by linking two outer or inner joined tables
to each other instead of a root containing all possible keys for both tables.
This example also introduces a limitation of SQL as joining more than one table
on the same columns where one of the source record sets contains more than one record
per join criteria causes row duplication to occur. */

-------------------------------------------------------------------------
-- Create schema.
-------------------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'BLOG2')
 EXEC sys.sp_executesql N'CREATE SCHEMA [BLOG2] AUTHORIZATION [dbo]'

-------------------------------------------------------------------------
-- Create example tables.
-------------------------------------------------------------------------
IF NOT OBJECT_ID('BLOG2.Entity') IS NULL DROP TABLE BLOG2.Entity
CREATE TABLE BLOG2.Entity(EntityID integer, EntityName varchar(50))

-- populate Entity with 3 records.
INSERT INTO BLOG2.Entity(EntityID, EntityName )
SELECT EntityID = 1, EntityName = 'Entity1'
UNION SELECT EntityID = 2, EntityName = 'Entity2'
UNION SELECT EntityID = 3, EntityName = 'Entity3'

-- Create EntityBase1 and populate it with 3 records.
IF NOT OBJECT_ID('BLOG2.EntityBase1') IS NULL DROP TABLE BLOG2.EntityBase1
CREATE TABLE BLOG2.EntityBase1 (EntityID integer, Period integer)
INSERT INTO BLOG2.EntityBase1 (EntityID,Period )
SELECT Entity = 1, Period = 201101
UNION SELECT Entity = 1, Period = 201102

-- Create EntityBase2 and populate it with 3 records.
IF NOT OBJECT_ID('BLOG2.EntityBase2') IS NULL DROP TABLE BLOG2.EntityBase2
CREATE TABLE BLOG2.EntityBase2 (EntityID integer, FromPeriod integer, ThroughPeriod integer)
INSERT INTO BLOG2.EntityBase2 (EntityID,FromPeriod, ThroughPeriod )
SELECT Entity = 1, FromPeriod = 201101, ThroughPeriod = 201103
UNION SELECT Entity = 2, FromPeriod = 201104, ThroughPeriod = 201107

-- Create the 1st table for monetary data.
IF NOT OBJECT_ID('BLOG2.EntityDetail1') IS NULL DROP TABLE EntityDetail1
CREATE TABLE BLOG2.EntityDetail1 (EntityID integer, period integer, Amount money)

-- insert 3 records
INSERT INTO BLOG2.EntityDetail1 (EntityID, period, Amount)
SELECT BaseTable.EntityID , BaseTable.period , BaseTable.Amount
FROM (
SELECT EntityID = 1, period = 201101, Amount = 50
UNION ALL SELECT EntityID = 1, period = 201101, Amount = 60
UNION ALL SELECT EntityID = 1, period = 201101, Amount = 70
) BaseTable

-- Create the 2nd table for monetary data.
IF NOT OBJECT_ID('BLOG2.EntityDetail2') IS NULL DROP TABLE BLOG2.EntityDetail2
CREATE TABLE BLOG2.EntityDetail2(EntityID integer, period integer, Amount money)

-- insert 3 monetary records
INSERT INTO BLOG2.EntityDetail2(EntityID, period, Amount)
SELECT BaseTable.EntityID , BaseTable.period , BaseTable.Amount
FROM (
SELECT EntityID = 1, period = 201101, Amount = 50
UNION ALL SELECT EntityID = 1, period = 201101, Amount = 40
UNION ALL SELECT EntityID = 1, period = 201102, Amount = 30
) BaseTable
-------------------------------------------------------------------------
-- End of DML
-------------------------------------------------------------------------

/*
SELECT * FROM BLOG2.EntityBase1 BaseTable

EntityID    Period
----------- -----------
1           201101
1           201102
(2 row(s) affected)

SELECT * FROM BLOG2.EntityDetail1 BaseTable

EntityID    period      Amount
----------- ----------- ---------------------
1           201101      50.00
1           201101      60.00
1           201101      70.00
(3 row(s) affected)


SELECT * FROM BLOG2.EntityDetail2 BaseTable

EntityID    period      Amount
----------- ----------- ---------------------
1           201101      50.00
1           201101      40.00
1           201102      30.00
(3 row(s) affected)

The next example will have a join causing omission of data. The join

        LEFT JOIN BLOG2.EntityDetail2 Join2 WITH (NOLOCK)
             ON Join1.EntityID = Join2.EntityID
            AND Join1.Period = Join2.Period

should actually be coded to link to the BaseTable as

      LEFT JOIN BLOG2.EntityDetail2 Join2 WITH (NOLOCK)
           ON BaseTable.EntityID = Join2.EntityID
           AND BaseTable.Period = Join2.Period

although that is not entirely correct as I have introduced an inherent SQL limitation in this example.

Here is our data.

--BLOG2.EntityBase1 BaseTable
EntityID Period
----------- -----------
1 201101
1 201102

--BLOG2.EntityDetail1 BaseTable
EntityID period Amount
----------- ----------- ---------------------
1 201101 50.00
1 201101 60.00
1 201101 70.00

--BLOG2.EntityDetail2 BaseTable
EntityID period Amount
----------- ----------- ---------------------
1 201101 50.00
1 201101 40.00
1 201102 30.00

Our EntityBase1 table only contains two records.
One for 201101 and one for 201102. Both for EntityId = 1
Our EntityDetail1 table contains 3 records for EntityId = 1. All three for period 201101.
Our EntityDetail2 table contains 3 records, 2 for 201101 and 1 for 201102.
In total we have 5 records for 201101 and 1 record for 201102 so in total we should have at most 6 records.
Due to invalid joins in the queries below we have 7 records returning however the 201102 data is not returned at all in the first query.
*/

SELECT
BaseTable.EntityID
, Period = BaseTable.Period
, Period1 =Join1.Period
, Join1Amount = Join1.Amount
, Period2 = Join2.Period
, Join2Amount = Join2.Amount
FROM BLOG2.EntityBase1 BaseTable WITH (NOLOCK)
LEFT JOIN BLOG2.EntityDetail1 Join1 WITH (NOLOCK)
                ON BaseTable.EntityID = Join1.EntityID
                AND BaseTable.Period = Join1.Period
LEFT JOIN BLOG2.EntityDetail2 Join2 WITH (NOLOCK)
             ON Join1.EntityID = Join2.EntityID
            AND Join1.Period = Join2.Period

/*
As you can see the values returned by this query do not reflect the actual data.

EntityID    Period      Period1     Join1Amount           Period2     Join2Amount
----------- ----------- ----------- --------------------- ----------- ---------------------
1           201101      201101      50.00                 201101      50.00
1           201101      201101      50.00                 201101      40.00
1           201101      201101      60.00                 201101      50.00
1           201101      201101      60.00                 201101      40.00
1           201101      201101      70.00                 201101      50.00
1           201101      201101      70.00                 201101      40.00
1           201102      NULL        NULL                  NULL        NULL

(7 row(s) affected)

Now lets try to query the data a bit differently. This example will fix one thing wrong with the
prior query but will leave one more thing to be fixed. In this example a base record set containing
all possible keys (EntityID,Period) for both tables is created. These values are then linked to the
tables containing the actual data. There is still a problem with this query. As discussed in the last
example both EntityDetail1 and EntityDetail2 need to link on the same columns (EntityID,Period) which causes row duplication when either join returns more than one record and has identical join criteria.
In the following query a fix to join2 has been implemented as a join on the BaseTable instead of join1.  Our 201102 data is now showing up however this is still not correct but let's see what the data is returned anyway. */

SELECT
  BaseTable.EntityID
, AllPossible.Period
, AmountBaseTable = Join1.Amount
, AmountJoin1 = Join2.Amount
FROM BLOG2.EntityBase1 BaseTable WITH (NOLOCK)
-- All possible
LEFT JOIN (
    SELECT EntityID , Period
    FROM BLOG2.EntityDetail1
    UNION -- Don't use UNION ALL as we want a distinct list to join on.
    SELECT EntityID , Period 
    FROM BLOG2.EntityDetail2
) AllPossible
   ON BaseTable.EntityID = AllPossible.EntityID
   AND BaseTable.Period = AllPossible.Period
-- Detail 1
LEFT JOIN BLOG2.EntityDetail1 Join1 WITH (NOLOCK)
   ON AllPossible.EntityID = Join1.EntityID
   AND AllPossible.Period = Join1.Period
-- Detail 2
LEFT JOIN BLOG2.EntityDetail2 Join2 WITH (NOLOCK)
   ON AllPossible.EntityID = Join2.EntityID
   AND AllPossible.Period = Join2.Period


/* As can be seen we still have row duplication issues.

EntityID    Period      AmountBaseTable       AmountJoin1
----------- ----------- --------------------- ---------------------
1           201101      50.00                 50.00
1           201101      50.00                 40.00
1           201101      60.00                 50.00
1           201101      60.00                 40.00
1           201101      70.00                 50.00
1           201101      70.00                 40.00
1           201102      NULL                  30.00
(7 row(s) affected)

In this example all possible records have been rolled up into 'AllPossible'
and the tables containing the monetary amounts have been formatted as one table
by using the UNION ALL operator. We need to make sure to use the UNION ALL operator as we don't want to lose any data. A flag is supplied to denote which table the
values come from.
*/

SELECT
   BaseTable.EntityID
 , AllPossible.Period
 , Join2.RecType
 , Join2.Amount
FROM BLOG2.EntityBase1 BaseTable WITH (NOLOCK)
 LEFT JOIN (
  SELECT
   EntityID
   , Period
  FROM BLOG2.EntityDetail1
  UNION
  SELECT
   EntityID
   , Period
  FROM BLOG2.EntityDetail2
 ) AllPossible
  ON BaseTable.EntityID = AllPossible.EntityID
  AND BaseTable.Period = AllPossible.Period

 LEFT JOIN (
  SELECT
   RecType = 1
   , *
  FROM BLOG2.EntityDetail1
  UNION ALL
  SELECT
   RecType = 2
   , *
  FROM BLOG2.EntityDetail2
 ) Join2
  ON AllPossible.EntityID = Join2.EntityID
  AND AllPossible.Period = Join2.Period

/*
We now have only 6 records returned and they all display the correct values.

EntityID    Period      RecType     Amount
----------- ----------- ----------- ---------------------
1           201101      1           50.00
1           201101      1           60.00
1           201101      1           70.00
1           201101      2           50.00
1           201101      2           40.00
1           201102      2           30.00
(6 row(s) affected)
Here is another version of the prior query. In this example we sum the values and display them side by side.
*/

SELECT
      BaseTable.EntityID
     , AllPossible.Period
     , AmountBaseTable = SUM(CASE WHEN Join2.RecType = 1 THEN Join2.Amount ELSE 0 END)
     , AmountJoin1 = SUM(CASE WHEN Join2.RecType = 2 THEN Join2.Amount ELSE 0 END)
FROM BLOG2.EntityBase1 BaseTable WITH (NOLOCK)
 LEFT JOIN (
  SELECT
   EntityID
   , Period
  FROM BLOG2.EntityDetail1
  UNION
  SELECT
   EntityID
   , Period
  FROM BLOG2.EntityDetail2
 ) AllPossible
  ON BaseTable.EntityID = AllPossible.EntityID
  AND BaseTable.Period = AllPossible.Period

 LEFT JOIN (
  SELECT
   RecType = 1
   , *
  FROM BLOG2.EntityDetail1
  UNION ALL
  SELECT
   RecType = 2
   , *
  FROM BLOG2.EntityDetail2
 ) Join2
  ON AllPossible.EntityID = Join2.EntityID
  AND AllPossible.Period = Join2.Period
GROUP BY BaseTable.EntityID , AllPossible.Period

/*
EntityID    Period      AmountBaseTable       AmountJoin1
----------- ----------- --------------------- ---------------------
1           201101      180.00                90.00
1           201102      0.00                  30.00

(2 row(s) affected)

Hopefully the examples I have provided will help the reader understand
how row duplication occurs in SQL statements and how to deal with
identical join criteria.  If both EntityDetail tables had unique record
constraints on (entityid,period) they could have have been linked to
AllPossible without causing row duplication.
*/

END
GO
-- Another Example.
-------------------------------------------------------------------------------
-- Here is an example of ommiting data by linked two outer or inner joined tables
-- to each other instead of a root containing all possible keys for both tables.
-------------------------------------------------------------------------------
SELECT  t1.InvestorID , t2.Period , t3.Period
FROM     dbo.InvestorBase t1 WITH (NOLOCK)
        LEFT JOIN dbo.InvestorDetail1 t2 WITH (NOLOCK) ON t1.InvestorID = t2.InvestorID 
        LEFT JOIN dbo.InvestorDetail2 t3 WITH (NOLOCK)  ON t2.InvestorID = t3.InvestorID 
                                                                                    AND t2.Period = t3.Period
                     

SELECT  t1.InvestorID , AllPossible.Period, Amount1 = t2.Amount, Amount2 = t3.Amount
FROM     dbo.InvestorBase t1 WITH (NOLOCK)
            LEFT JOIN (
                  SELECT InvestorID , Period  FROM dbo.InvestorDetail1
                  UNION
                  SELECT InvestorID , Period  FROM dbo.InvestorDetail2
            ) AllPossible
                  ON t1.InvestorID  = AllPossible.InvestorID 
                  AND t1.Period = AllPossible.Period

            LEFT JOIN dbo.InvestorDetail1 t2 WITH (NOLOCK) ON AllPossible.InvestorID = t2.InvestorID 
                                                                                    AND AllPossible.Period = t2.Period
            LEFT JOIN dbo.InvestorDetail2 t3 WITH (NOLOCK)  ON AllPossible.InvestorID = t3.InvestorID 
                                                                                    AND AllPossible.Period = t3.Period

Thursday, June 23, 2011

Database Development - Row Duplication 1

CREATE PROCEDURE [dbo].[usp_blg_vkj_0000001] AS
BEGIN

--Row duplication caused by a join to a non-unique index./* Data problems can often be identified without actually checking data as a developer can sometimes recognize
when data returned would be invalid just by reviewing the sql used to return the data. I have already demonstrated row duplication caused by Cartesian or cross joins in a previous blog article so I will only review two other examples here.

This example demonstrates row duplication caused by a join to a non-unique index or row duplication
caused by joining a base table foreign key to what is supposed to be the primary key of a CodeListBaseTable or look up table. For this example we have not implemented a unique index on the CodeListBaseTable. */

-------------------------------------------------------------------------
-- Create schema.
-------------------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'BLOG1')
 EXEC sys.sp_executesql N'CREATE SCHEMA [BLOG1] AUTHORIZATION [dbo]'

-- Populate our BaseTable.
IF NOT OBJECT_ID('BLOG1.BaseTable') IS NULL DROP TABLE BLOG1.BaseTable

CREATE TABLE BLOG1.BaseTable(RecId integer, ListCode integer)

INSERT INTO BLOG1.BaseTable(RecId, ListCode )
SELECT RecId = 1, ListCode = 1
UNION ALL SELECT RecId = 2, ListCode = 2
UNION ALL SELECT RecId = 3, ListCode = 3

-- Populate the coldelist table.
IF NOT OBJECT_ID('BLOG1.CodeList1') IS NULL DROP TABLE BLOG1.CodeList1

CREATE TABLE BLOG1.CodeList1(CodeID integer, CodeValue varchar(50))

INSERT INTO BLOG1.CodeList1(CodeID , CodeValue )
SELECT CodeID = 1, CodeValue = 'CodeList1Value1'
UNION ALL SELECT CodeID = 2, CodeValue = 'CodeList1Value2'
UNION ALL SELECT CodeID = 3, CodeValue = 'CodeList1Value3'

-- Populate the coldelist table.
IF NOT OBJECT_ID('BLOG1.CodeList2') IS NULL DROP TABLE BLOG1.CodeList2

CREATE TABLE BLOG1.CodeList2(CodeID integer, CodeValue varchar(50))

INSERT INTO BLOG1.CodeList2(CodeID , CodeValue )
SELECT CodeID = 1, CodeValue = 'CodeList2Value1'
UNION ALL SELECT CodeID = 2, CodeValue = 'CodeList2Value2'
UNION ALL SELECT CodeID = 3, CodeValue = 'CodeList2Value3'

/* The query below returns good data but since there is no unique record constraint
on the BaseTable table there is still a potential problem. */

SELECT BaseTable.RecId , BaseTable.ListCode , Join1.CodeValue
FROM BLOG1.BaseTable BaseTable
 left join BLOG1.CodeList1 Join1 ON BaseTable.ListCode = Join1.CodeID

/*
RecId       ListCode    CodeValue
----------- ----------- --------------------------------------------------
1           1           CodeList1Value1
2           2           CodeList1Value2
3           3           CodeList1Value3

(3 row(s) affected)

Now let's add a duplicate Code ID in the BaseTable table to see what happens.
In real life a unique constraint should exist so this can not occur.

Note: Normally you should have a unique index on both the code Id and code value.
A common mistake is to just put one on the code id and let duplicates occur in the code value.
*/

--Modify the data for our next example.
IF NOT OBJECT_ID('BLOG1.CodeList1') IS NULL DROP TABLE BLOG1.CodeList1

CREATE TABLE BLOG1.CodeList1(CodeID integer, CodeValue varchar(50))

INSERT INTO BLOG1.CodeList1(CodeID , CodeValue )
SELECT CodeID = 1, CodeValue = 'CodeList1Value1'
UNION ALL SELECT CodeID = 2, CodeValue = 'CodeList1Value2'
UNION ALL SELECT CodeID = 3, CodeValue = 'CodeList1Value3'
UNION ALL SELECT CodeID = 1, CodeValue = 'CodeList1Value4'

/*
SELECT * FROM BLOG1.CodeList1 BaseTable

CodeID      CodeValue
----------- --------------------------------------------------
1           CodeList1Value1
2           CodeList1Value2
3           CodeList1Value3
1           CodeList1Value4
(4 row(s) affected)
*/

--Modify the data for our next example.IF NOT OBJECT_ID('CodeList2') IS NULL DROP TABLE CodeList2

IF NOT OBJECT_ID('BLOG1.CodeList2') IS NULL DROP TABLE BLOG1.CodeList2

CREATE TABLE BLOG1.CodeList2(CodeID integer, CodeValue varchar(50))

INSERT INTO BLOG1.CodeList2(CodeID , CodeValue )
SELECT CodeID = 1, CodeValue = 'CodeList2Value1'
UNION ALL SELECT CodeID = 2, CodeValue = 'CodeList2Value2'
UNION ALL SELECT CodeID = 3, CodeValue = 'CodeList2Value3'
UNION ALL SELECT CodeID = 1, CodeValue = 'CodeList2Value4'

/*

SELECT * FROM BLOG1.CodeList2 BaseTable

CodeID      CodeValue
----------- --------------------------------------------------
1           CodeList2Value1
2           CodeList2Value2
3           CodeList2Value3
1           CodeList2Value4

(4 row(s) affected)

Row duplication occurs in the following example since we no longer have a unique value
on either side of the join. There are only 3 records in the base table however row duplication
returns more records. */

SELECT
    BaseTable.RecId
   , BaseTable.ListCode
   , Join1.CodeValue
-- BaseTable contains 3 records
FROM BLOG1.BaseTable BaseTable
-- join1: CodeListBaseTable contains 4 records with one duplicate code.
    left join BLOG1.CodeList1 Join1 WITH (NOLOCK) ON BaseTable.ListCode = Join1.CodeID

 /*

RecId       ListCode    CodeValue
----------- ----------- --------------------------------------------------
1           1           CodeList1Value1
1           1           CodeList1Value4
2           2           CodeList1Value2
3           3           CodeList1Value3

(4 row(s) affected)

Now see what happens when you not only are linking without a unique ID on either side of join1 but are also linking without a unique ID on either side of join2. Row duplication occurs in the following example since we no longer have a unique value.
There are only 3 records in the base table however row duplication returns more records. */

SELECT 
    BaseTable.RecId
  , BaseTable.ListCode
   , CodeListBaseTableValue = Join1.CodeValue
   , CodeListJoin1Value = Join2.CodeValue
-- BaseTable contains 3 records
FROM BLOG1.BaseTable BaseTable
-- join1: CodeList1 contains 4 records with one duplicate code.
     left join BLOG1.CodeList1 Join1 WITH (NOLOCK) ON BaseTable.ListCode = Join1.CodeID
  -- join2: CodeList2 contains 4 records with one duplicate code
     left join BLOG1.CodeList2 Join2 WITH (NOLOCK) ON BaseTable.ListCode = Join2.CodeID
ORDER BY Join1.CodeValue , Join2.CodeValue

/* There are only 3 records in our base table so it is obvious row duplication is occurring.
We have row duplication occuring from the first join causing the base recordset to return 4 records.
The reason for the row duplication is due to the join not being based on the base table foreing key
value joined to code table primary keys. At least one side of the join has to identify a single record.
We also have row duplication occuring from the second join for the same reason. Row duplication is not only being caused by the joins not being based on the base table foreing key values joined to code table primary keys but also because CodeList1 and CodeList2 are both linking on the same join criteria which is not allowed in SQL unless only one record is returned for each join. These joins would be fine and the normal way to query a codelist table if we put a primary keys and unique record constraints on our codelist tables.

RecId       ListCode    CodeListBaseTableValue                             CodeListJoin1Value
----------- ----------- -------------------------------------------------- --------------------------------------------------
1           1           CodeList1Value1                                    CodeList2Value1
1           1           CodeList1Value1                                    CodeList2Value4
2           2           CodeList1Value2                                    CodeList2Value2
3           3           CodeList1Value3                                    CodeList2Value3
1           1           CodeList1Value4                                    CodeList2Value1
1           1           CodeList1Value4                                    CodeList2Value4

(6 row(s) affected)

*/

END

Tuesday, June 14, 2011

Database Development - Cartesian joins to generate dates

It seems every time I hear the phrase 'cartision join' it's mentioned in a negative way. Cartesian joins also called cross joins are a type of table join great for building things, you just need to understand what they are and how they work to make them useful. A Cartesian join occurs in an SQL statement when one or more tables are cross joined on the other tables. This also occurs when you use old SQL syntax like FROM t1,t2 without a WHERE t1.recid=t2.recid join filter to link the tables. Row duplication occurs when records are linked this way causing all the records in one table to be returned for each record in the other table. In this example we are intentionally using row duplication to build a set of dates and then using a function to filter out invalid dates like '06/31/2011'. Actually in this example I delete the dates I do not want but the functionality is the same. 

e.x. 

FROM  @Year y
      CROSS JOIN @Month m
      CROSS JOIN @Day d
WHERE (ISDATE( CAST(M.intMonth as varchar(2))
      + '/' + CAST(d.intDay as varchar(2))
      + '/' + CAST(Y.intYear as varchar(4)))) = 1

This provides the data available to filter further by date range. If you spend anytime designing procedures to populate reports you will need a user defined table to generate dates for you as shown below.

SELECT *
FROM [dbo].[udt_GenerateDates]('6/1/2011','6/14/2011')


GeneratedDate GeneratedYear GeneratedMonth GeneratedDay
----------------------- ------------- -------------- ------------
2011-06-01 00:00:00.000 2011 6 1
2011-06-02 00:00:00.000 2011 6 2
2011-06-03 00:00:00.000 2011 6 3
2011-06-04 00:00:00.000 2011 6 4
2011-06-05 00:00:00.000 2011 6 5
2011-06-06 00:00:00.000 2011 6 6
2011-06-07 00:00:00.000 2011 6 7
2011-06-08 00:00:00.000 2011 6 8
2011-06-09 00:00:00.000 2011 6 9
2011-06-10 00:00:00.000 2011 6 10
2011-06-11 00:00:00.000 2011 6 11
2011-06-12 00:00:00.000 2011 6 12
2011-06-13 00:00:00.000 2011 6 13
2011-06-14 00:00:00.000 2011 6 14

(14 row(s) affected)


Here is the user defined table function.

CREATE FUNCTION [dbo].[udt_GenerateDates](
@DateFrom datetime
, @DateTo datetime
)
RETURNS @TableVar table (
GeneratedDate DateTime
, GeneratedYear int
, GeneratedMonth int
, GeneratedDay int
)
AS
BEGIN
----------------------------------
-- Declare variables
----------------------------------
DECLARE @intYear integer
DECLARE @intYearTo integer
DECLARE @intDay integer
DECLARE @intMonth integer
DECLARE @Year table (intYear int)
DECLARE @Month table (intMonth int)
DECLARE @Day table (intDay int)
----------------------------------
-- Initialize Defaults
----------------------------------
SET @intYear = DATEPART(YYYY, @DateFrom) - 1
SET @intYearTo = DATEPART(YYYY, @DateTo)


-- Build Years
WHILE @intYear < @intYearTo
BEGIN
   SET @intYear = @intYear + 1
   INSERT INTO @Year(intYear)
   VALUES (@intYear)
END

-- Build Months
SET @intMonth = 0
WHILE @intMonth < 12
BEGIN
   SET @intMonth = @intMonth + 1
   INSERT INTO @Month(intMonth)
   VALUES (@intMonth)
END

-- Build Days
SET @intDay = 0
WHILE @intDay < 31
BEGIN
   SET @intDay = @intDay + 1
   INSERT INTO @Day(intDay)
   VALUES(@intDay )
END

----------------------------------
-- Cross join the tables to produce
-- all possible date values.
----------------------------------

INSERT INTO @TableVar(
  GeneratedDate
, GeneratedYear
, GeneratedMonth
, GeneratedDay
)
SELECT
  GeneratedDate  = CAST(M.intMonth as varchar(2))
                   + '/' + CAST(d.intDay as varchar(2))
                   + '/' + CAST(Y.intYear as varchar(4))
, GeneratedYear  = Y.intYear
, GeneratedMonth = M.intMonth
, GeneratedDay   = d.intDay
FROM @Year y
     CROSS JOIN @Month m
     CROSS JOIN @Day d
WHERE ISDATE(         CAST(M.intMonth as varchar(2))
              + '/' + CAST(d.intDay as varchar(2))
              + '/' + CAST(Y.intYear as varchar(4))
             ) = 1

-- Delete unwanted dates
DELETE FROM @TableVar
WHERE GeneratedDate < CONVERT(varchar(10), @DateFrom, 101)
OR GeneratedDate > @DateTo


RETURN
END
GO