Welcome to EMC Consulting Blogs Sign in | Join | Help

Third Abnormal Form

Resolution to SQL Server problems. From the front line.

  • Using the SQL 2008 VALUES Statement to Create data for a Numbers or Tally Table

    You often want to create a Numbers (sometimes called) Tally Table in SQL Server, to help with Set Based calculations.

     To see what a Numbers table is read:

     http://www.sqlservercentral.com/articles/T-SQL/62867/

    Prior to SQL Server 2008 I have also used a Dervived UNION ALL Statement to create a simple Numbers table at run time, along the lines of

    SELECT 1 AS Number

    UNION ALL

    SELECT 2 AS Number

    UNION ALL

    SELECT 3 AS Number

    UNION ALL

    SELECT 4 AS Number

    UNION ALL

    SELECT 5 AS Number;

    However, there is an easier way of doing this now... using the new VALUES Clause in SQL Server 2008, This does NOT have to be used simply for Inserting multiple rows into a table, without writing the INSERT Statement loits of times, you can use it for other T-SQL uses.. like:

     You can simply write: 

    SELECT Number FROM (VALUES(1),(2),(3),(4),(5)) AS D (Numbers);

    I don't know the performance impact of this, but it is another way of doing this...

     

     

     

  • Another good use for SQL 2008 VALUES Clause in Views

    Sometimes you need to create some 'permanent' data in a View (rather than a Table), to be used for coding purposes. This is often used to 'get around' a problem due to lack of data or time to create a table that might only be used for a small period of time.. On tmy current project we have a number of 'look up Views' for data we may need to change quickly before we go live. An example of how you woudl noirmally do this is shown below.. This can be quite tiresome to code if you have 2000 rows rather than 20..

    CREATE VIEW PremershipClubs20092010 AS

    SELECT 'Arsenal' AS ClubName, 1 AS NameOrder UNION ALL

    SELECT 'Aston Villa', 2 UNION ALL

    SELECT 'Birmingham City', 3 UNION ALL

    SELECT 'Blackburn Rovers', 4 UNION ALL

    SELECT 'Bolton Wanderers', 5 UNION ALL

    SELECT 'Burnley', 6 UNION ALL

    SELECT 'Chelsea', 7 UNION ALL

    SELECT 'Everton', 8 UNION ALL

    SELECT 'Fulham', 9 UNION ALL

    SELECT 'Hull City', 10 UNION ALL

    SELECT 'Liverpool', 11 UNION ALL

    SELECT 'Manchester City', 12 UNION ALL

    SELECT 'Manchester United', 13 UNION ALL

    SELECT 'Portsmouth', 14 UNION ALL

    SELECT 'Stoke City', 15 UNION ALL

    SELECT 'Sunderland', 16 UNION ALL

    SELECT 'Tottenham Hotspur', 17 UNION ALL

    SELECT 'West Ham United', 18 UNION ALL

    SELECT 'Wigan Athletic', 19 UNION ALL

    SELECT 'Wolverhampton Wanderers', 20;

    SELECT * FROM PremershipClubs20092010;

    How much easier, quicker and simplier is it to maintain the following (if you have add and remove teams, and re-order the daatfor 2010 /2011 Season) ? Again using the VALUES Clause, this is slightly less code!!..

     

    CREATE VIEW PremershipClubs20092010_New

    AS

    SELECT ClubName, NameOrder FROM (VALUES

    ('Arsenal', 1),

    ('Aston Villa', 2),

    ('Birmingham City', 3),

    ('Blackburn Rovers', 4),

    ('Bolton Wanderers', 5),

    ('Burnley', 6),

    ('Chelsea', 7),

    ('Everton', 8),

    ('Fulham', 9),

    ('Hull City', 10),

    ('Liverpool', 11),

    ('Manchester City', 12),

    ('Manchester United', 13),

    ('Portsmouth', 14),

    ('Stoke City', 15),

    ('Sunderland', 16),

    ('Tottenham Hotspur', 17),

    ('West Ham United', 18),

    ('Wigan Athletic', 19),

    ('Wolverhampton Wanderers', 20)) AS D (ClubName, NameOrder);

    SELECT * FROM PremershipClubs20092010_New;

     

    Again I do not know performance impacts?

  • SQL03006: VS 2010 RC 'contains an unresolved reference to an object.' Possible Solution

    Had the following error today

     Error 42 SQL03006: Column: [General].[Check_Transform].[A_COLUMN_NAME] contains an unresolved reference to an object. Either the object does not exist or the reference is ambiguous because it could refer to any of the following objects: [INFORMATION_SCHEMA].[COLUMNS].Angel::[COLUMN_NAME] or [INFORMATION_SCHEMA].[COLUMNS].[COLUMN_NAME]. 

    Same on 7 other rows.. 

    Googled the life out of it no luck :-(

    The query was this

    CREATE VIEW TEST

    AS

    A.TABLE_SCHEMA +'.' + A.TABLE_NAME + '<->' + B.TABLE_SCHEMA + '.' + B.TABLE_NAME AS Pair,

    A.COLUMN_NAME AS A_COLUMN_NAME,

    B.COLUMN_NAME AS B_COLUMN_NAME,

    A.DATA_TYPE AS A_DATA_TYPE,

    B.DATA_TYPE AS B_DATA_TYPE,

    A.COLLATION_NAME AS A_COLLATION_NAME,

    B.COLLATION_NAME AS B_COLLATION_NAME,

    A.CHARACTER_OCTET_LENGTH AS A_CHARACTER_OCTET_LENGTH,

    B.CHARACTER_OCTET_LENGTH AS B_CHARACTER_OCTET_LENGTH

    FROM INFORMATION_SCHEMA.COLUMNS A

    INNER JOIN INFORMATION_SCHEMA.COLUMNS B

    ON A.TABLE_SCHEMA = B.TABLE_SCHEMA

    AND A.ORDINAL_POSITION = B.ORDINAL_POSITION

    WHERE A.TABLE_SCHEMA = @TABLE_SCHEMA

    AND A.TABLE_NAME = @A_TABLE_NAME

    AND B.TABLE_NAME = @B_TABLE_NAME

    AND (

    A.COLUMN_NAME <> B.COLUMN_NAME

    OR A.DATA_TYPE <> B.DATA_TYPE

    OR A.COLLATION_NAME <> B.COLLATION_NAME

    OR A.CHARACTER_OCTET_LENGTH<> B.CHARACTER_OCTET_LENGTH

    );

    I noticed we didn't get anything on first line which had some sort of function applied to the column (it passed). There must be a bug in VS 2010 RC. Solved it by adding 'false function'

    SELECT A.TABLE_SCHEMA +'.' + A.TABLE_NAME + '<->' + B.TABLE_SCHEMA + '.' + B.TABLE_NAME AS Pair,

    LTRIM(A.COLUMN_NAME) AS A_COLUMN_NAME, -- Does not change result

    LTRIM(B.COLUMN_NAME) AS B_COLUMN_NAME,

    LTRIM(A.DATA_TYPE) AS A_DATA_TYPE,

    LTRIM(B.DATA_TYPE) AS B_DATA_TYPE,

    LTRIM(A.COLLATION_NAME) AS A_COLLATION_NAME,

    LTRIM(B.COLLATION_NAME) AS B_COLLATION_NAME,

    0 + A.CHARACTER_OCTET_LENGTH AS A_CHARACTER_OCTET_LENGTH, -- Does not change result (Null still a Null)

    0 + B.CHARACTER_OCTET_LENGTH AS B_CHARACTER_OCTET_LENGTH

    FROM INFORMATION_SCHEMA.COLUMNS A

    INNER JOIN INFORMATION_SCHEMA.COLUMNS B

    ON A.TABLE_SCHEMA = B.TABLE_SCHEMA

    AND A.ORDINAL_POSITION = B.ORDINAL_POSITION

    WHERE A.TABLE_SCHEMA = @TABLE_SCHEMA

    AND A.TABLE_NAME = @A_TABLE_NAME

    AND B.TABLE_NAME = @B_TABLE_NAME

    AND (

    A.COLUMN_NAME <> B.COLUMN_NAME

    OR A.DATA_TYPE <> B.DATA_TYPE

    OR A.COLLATION_NAME <> B.COLLATION_NAME

    OR A.CHARACTER_OCTET_LENGTH<> B.CHARACTER_OCTET_LENGTH

    );

     

    And it passed Build in VS 2010 OK.. Hope it helps someone else!


     

  • Just a quickie - In SQL Server 2005, if you Filter on a BIT Field please use 'TRUE' or 'FALSE' not 1 or 0

    Well it's 2008 so I better post another Blog entry. Just a quick note though as after tearing my hair out for best part of a day, I have found an interesting 'feature' with BIT Fields in SQL Server 2005 and a SSIS Data Flow OLE-DB Source (though I suspect it occurs elsewhere within SSIS and maybe SSMS, and the behaviour did not occur when I ran something interactively, it only occurred when the SSIS Package was executed as Job i.e a real **&^&%$ to find

    Basically, OLE_DB Source query was doing the following in a derived table against a SQL Server 2005 database

    SELECT Column FROM dbo.Table WHERE ColumnFlag = 1;

    The ColumnFlag was defined as a BIT field on a Table. However, when I ran the code via a Job I was finding it effectively ignored the WHERE ColumnFlag = 1 filter. I wondered if this was because in SQL Server 2005 Microsoft have changed the behaviour of BIT fields and introduced the new keywords 'TRUE' and 'FALSE' - Sure enough, as soon as I changed the code to be:

    SELECT Column FROM dbo.Table WHERE ColumnFlag = 'TRUE';

    It worked as I wanted.

    So I have decided that whenever I use BIT Fields in SQL Server 2005 I will now use 'TRUE' and 'FALSE' - Not 1 and 0, another convention change I will just have to get use to until it becomes second nature Like ANSI 92 and Statement Termination;

    Note: 'TRUE' and 'FALSE' will n ot work against a SQL Server 2000 database, you will need to use the old convention

  • Forcing Order in an Execution Plan (SQL 2000) and Performance Coding Challenge

    We have the following in SQL Server 2000

    27 Partition Fact Tables containing Sales Data: Supplier, Product, Store and Day held in a Union All View SupplierProductStoreDay (over 1.35 Billion records)


    We have another table that says ‘ProductPromotion’ which has a Start Date and End Date Promotion Period, when a Product is on Promotion


    We require a Flag (ProductSaleWithinPeriodFlag that answers the question, this Product is on a Promotion, but did it have any sales YES/NO (1/0) on any Date during the Promotion Period

     

    So the question that is needed to be answered is ‘Did we sell this Product in any Store during the Period?’ – The point is we know as SOON as we find the Sale in any Store (and in fact for any Supplier and Date within the Promotion Period), we can STOP searching for anymore.


    However, if we do a MIN, MAX we still have to read all the data to determine the MIN or MAX figure, we just want a FIRST or ANY function (to check the existence), in SQL 2005 we could use a CLR Function to do this, but we need it in SQL 2000. And we want it as performant as we can get and we need to do it in a View, so the answer is determined at Run Time for loading overnight into an Analysis Services 2005 Dimension.


    If anyone is interested I have a solution that solved this via UDF (however, using Table UDF – But as not as an In-line Function and not in the Where or Join Condition)


    The time to return the Flag (Yes/No Sales) data for 86,000 ProductPromotions (Products on Promotion) against 27 Months worth of Sales Data (1,350,000,000 rows) is 25 Minutes – Which  is OK as it will be loaded into an Analysis Services Cube, so we only need it at Dimension Creation Time


    The way I did was as follows

     

    SELECT

    X.ProductID,

                X.PromotionID,

                X.PromotionPeriodStartDateID,

                X.PromotionPeriodEndDateID,

                CASE WHEN MAX(Y.ProductID) IS NULL THEN 0 ELSE 1 END As ProductSaleWithinPeriodFlag

    FROM dbo.MyProductPromotionUDF AS X

    LEFT OUTER JOIN

                (

                SELECT

    ProductID,

                            BusinessDateID

                FROM dbo.SupplierProductStoreDay – Union ALL View

                GROUP BY ProductID, BusinessDateID

                ) AS Y

    ON Y.ProductID = X.ProductID

    AND Y.BusinessDateID >= X.PromotionPeriodStartDateID AND Y.BusinessDateID <= X.PromotionPeriodEndDateID

    GROUP BY

    X.ProductID,

                X.PromotionID,

                X.PromotionPeriodStartDateID,

                X.PromotionPeriodEndDateID

     

    It is important to use the dbo.MyProductPromotionUDF as a UDF Function to get the ‘working/filtered’ Product Promotion list as if you do not the Query Engine will evaluate ProductPromotion/SupplierProductStoreDay combination and then choose a  ‘really inefficient query engine’ and the time to work it out is INCREASED from 25 minutes to 3 hours.


    Note: A key point is that the use of a Table UDF ‘forces’ SQL Server to process/execute that part of the Execution plan first then use the results to generated to process against the LEFT OUTER JOIN against the SupplierProductStoreDay – Union ALL View. Which is a neat way of ‘forcing’ some order into your execution plan!

     

    BTW. I needed to use a GETDATE() in my dbo.MyProductPromotionUDF Function and you can’t (it is a non-deterministic function)! – A work around to put the SELECT GetDate() AS CurrentDateTime into a View: vGetDate and call the View in the UDF. I am not worried out any inconsistency as I am only after the current date, and not the time component:

     

    See: http://sqlserver2000.databases.aspfaq.com/how-do-i-use-getdate-within-a-user-defined-function-udf.html


    Also I have an added filters into dbo.MyProductPromotionUDF as I do not want to process ALL the Promotions that have ever been run, only those that exist for those dates we have data in the SupplierProductStoreDay for (reduces the number of Products and Periods to Join against in the Left Outer Join)

     

    To understand, the Business requirement to set this Flag, even though we have around 90,000 ProductPromotions only 86,000 ProductPromotions are valid in the 27 months, and from that we only have sales for around 50% (44,000) of these. Thus we are currently wasting Analysis Services processing time ‘looking for sales data’ which we will do not have. By using this Flag, we can filter out looking for these Products beforehand.

  • MSDTC Error 8522

    I will be using this medium for occasional musings on SQL Server. Especially when I resolve a problem which I believe may help others…

     

    My first posting concerns an MSDTC Error 8522 that a client was experiencing. This is a common problem with many causes (just try googling it), I believe I have identified one problem and resolution and I am posting it here to help others. The problem could be summarised as due to Transactional Scope.

     

    A client was encountering a periodic problem on a number of child nodes in the upstream data transfer load process, whereby data is transferred from a child node to a parent node under the control of a Linked Server, MSDTC and SQL Server Agent. They were running SQL Server 2000 Personal Edition running on XP SP1.

     

    The client has a number of these child nodes and was getting, the following error message in SQL Server. Once a child node started to generate the error message, then it would repeatedly fail. Other child nodes with exactly the same code base would continue to work OK (i.e. the worse problems to solve because they are intermittent!)

     

    Executed as user: <Domain_Name>\<SQL_Server_Service_Account>. Distributed transaction aborted by MSDTC. [SQLSTATE 42000] (Error 8522).  The step failed.

     

    MSDTC is an acronym for Microsoft Distributed Transaction Coordinator which is a Windows service providing transaction infrastructure for distributed systems.

     

    The client had undertaken a number of attempts to resolve the problem, including using tools such as DTCPing and DTCTester. Please see Florin Lazar's Blog for these:

     

    http://blogs.msdn.com/florinlazar/archive/2005/09/16/469064.aspx

     

    I was asked to investigate the issue and try and identify a solution. Normally, I would have recommended using the tools listed above, and looked at Security settings (notably TurnOffRpcSecurity) to resolve this problem, as this had worked successfully at other clients but this only applies to XP SP2 (not SP1). Again see Florin Lazar's Blog for this

     

    http://blogs.msdn.com/florinlazar/archive/2004/06/18/159127.aspx

     

    It was soon evident that this was different problem entirely and required more radical thought to resolve.

     

    The problem was isolated to a stored procedure I will call TransferDataToParent. I reviewed this stored procedure and discovered a couple of areas which gave me concern:

     

    • It was over engineered for its purpose, as it was invoking superfluous local transactions
    • It was undertaking combined local and distributed transactions in a single unit of work.

    I wondered if this was the second point was cause of the problem, and that MSDTC was getting ‘confused’ over what was the scope of a local transaction and the scope of a distributed transaction.

     

    Basically (at a high level) the stored procedure performed 3 functions:

     

    1)       Obtained data to transfer up the hierarchy in a series of SQL Server table variables (@table) under the control of a local transaction

    2)       Obtained secondary data into a local table variable (@table) and attempted to transfer this data to the parent node all under the control of a Distributed Transaction

    3)       Transferred the data obtained in Function 1) to the parent node in a Distributed Transaction

     

    It was determined that the process was failing at Function 2). However, I was concerned with Functions 1) and 2) for the following reasons

     

    • Function 1) - This is in a superfluous Transaction. The data was being stored into a series of table variables (@tables). @tables and # temporary tables are both non-persistent data stores. In the case of @tables, these are located in SQL Server memory and not on disk. Therefore a transaction is not needed, because if the code fails, then the data is automatically lost anyway. This does not need transactional control.

     

    • Function 2) – This process met two different requirements:

     

    a)       Obtaining data in local memory tables (@tables) but within a Distributed Transaction

    b)       Transferring the data to the parent node within the same Distributed Transaction

     

    I realised that a) should NOT be in a Distributed Transaction as it is an extension of the process in Function 1 above. Furthermore, MSTDC was probably also getting confused with attempting to perform a Distributed Transaction on local data (and with a @table variable as well!) – all within the same transactional scope.

     

    Therefore, I rewrote the stored procedure to remove these areas of concern, namely:

     

    • Obtain all data in local table variables outside of any transaction (local or distributed)
    • Ensured all data transfers up the hierarchy were purely under the control of a Distributed Transaction (i.e. reduced transaction scope)

     

    This worked successfully on two child nodes, that were previously having this problem and I now believe this problem to be resolved.

     

    In summary, this may not be the cause of your particular MSDTC Error 8522 problem, but I would recommend that you look at the scope of the distributed transaction, are you combining it with a local transaction and/or non-persistent data?

     

     

Powered by Community Server (Personal Edition), by Telligent Systems