Select Statement Where Column Does Not Exist

  • I bulk insert a file into a temp table each month.  The file has about 60 fields but sometimes 2 or 3 fields are missing (if they are missing its the same all the time).  I'd like to use the same procedure to read the temp table, whether it has 57, 58, 59 or 60 fields.  I played around with this but can't seem to come up with a solution.

    In the example the query reads #test1 but not #test2.  In this simplified example I'd like the same query to work on both tables (but remember I might have several fields missing).  I's like to do something like this (know this does not work):

    SELECT A, B, C, CASE IF D EXISTS THEN D ELSE 0 END as D FROM #Test2

    IF OBJECT_ID('tempdb..#Test1') IS NOT NULL DROP TABLE #Test1
    CREATE TABLE #Test1
    (A int, B int, C int, D int)
    INSERT INTO #Test1 SELECT 1,1,1,1
    INSERT INTO #Test1 SELECT 2,2,2,2

    -- SELECT A,B,C,D FROM #Test1

    IF OBJECT_ID('tempdb..#Test2') IS NOT NULL DROP TABLE #Test2
    CREATE TABLE #Test2
    (A int, B int, C int)
    INSERT INTO #Test2 SELECT 1,1,1
    INSERT INTO #Test2 SELECT 2,2,2

    -- SELECT A,B,C,D FROM #Test1
    -- SELECT A,B,C,D FROM #Test2

    IF OBJECT_ID('tempdb..#FieldExist') IS NOT NULL DROP TABLE #FieldExist
    SELECT [name] as FieldExist INTO #FieldExist FROM tempdb.sys.columns WHERE object_id = Object_id('tempdb..#test2')

    --this does not work
    SELECT CASE WHEN (SELECT * FROM #FieldExist WHERE FieldExist = 'D') IS NULL THEN 0 ELSE D END FROM #test2

    Thank you for your help!

     

     

     

     

  • I have one idea I haven't tried yet (think it will work):

    (1) import data into temp file

    (2) use alter database to add the missing fields if they do not exist

    I'd still be open to other ideas.  Thanks

     

  • dallastexas wrote:

    I have one idea I haven't tried yet (think it will work):

    (1) import data into temp file

    (2) use alter database to add the missing fields if they do not exist

    I'd still be open to other ideas.  Thanks

    I was thinking along the same lines – this is a decent solution. The 100% dynamic solutions will probably require the use of dynamic SQL, whereas this one should not (as long as you have a known list of the columns which may be missing). Personally, I avoid dynamic SQL where possible, so I would go with this.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Yes, I was also thinking from a maintenance perspective dynamic would not be the best solution.  Today its 3 missing, it might be 5 in the future so adding the missing field using alter is a quick fix.

    Thank you.

  • This is a simplified example of what I'm going to use as the solution:

    IF OBJECT_ID('tempdb..#Test2') IS NOT NULL DROP TABLE #Test2
    CREATE TABLE #Test2
    (A int, B int, C int)
    INSERT INTO #Test2 SELECT 1,1,1
    INSERT INTO #Test2 SELECT 2,2,2

    --is column D missing?
    IF NOT EXISTS (SELECT * from tempdb.sys.columns where object_id = object_id('tempdb..#Test2') AND [name] = 'D')
    ALTER TABLE #Test2
    ADD D int

    --is column E missing?
    IF NOT EXISTS (SELECT * from tempdb.sys.columns where object_id = object_id('tempdb..#Test2') AND [name] = 'E')
    ALTER TABLE #Test2
    ADD E int

    --is column F missing?
    IF NOT EXISTS (SELECT * from tempdb.sys.columns where object_id = object_id('tempdb..#Test2') AND [name] = 'F')
    ALTER TABLE #Test2
    ADD F int

    --if there is a column C, rename it to CC
    IF EXISTS (SELECT * from tempdb.sys.columns where object_id = object_id('tempdb..#Test2') AND [name] = 'C')
    EXEC tempdb.sys.sp_rename N'#Test2.C', N'CC', N'COLUMN';

    SELECT * FROM #Test2
  • Some of your SQL syntax can be refined a little (not that there was anything wrong with yours):

    DROP TABLE IF EXISTS #Test2;

    CREATE TABLE #Test2
    (
    A INT
    ,B INT
    ,C INT
    );

    INSERT #Test2
    (
    A
    ,B
    ,C
    )
    VALUES
    (1, 1, 1)
    ,(2, 2, 2);

    IF COL_LENGTH('#Test2', 'D') IS NULL
    BEGIN
    ALTER TABLE #Test2 ADD D INT;
    END;

    --Etc.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Thank you, that is a lot cleaner.

  • Be sure to specify NULL rather than letting nullability default, because the default might be NOT NULL, which would cause an error.

    ALTER TABLE #Test2

    ADD D int NULL;

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • You said that the files that are missing columns are the same except for the missing columns.  With that in mind, it's a whole lot easier if you make multiple BCP Format Files to control the Bulk Inserts.  You could even control which format file to use by reading just the first row as a blob, splitting it, and checking which columns aren't there according to sys.columns for the table.

    Shoot, for that matter, you could build the format files on the fly using a similar method just in case you get a surprise.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden wrote:

    You said that the files that are missing columns are the same except for the missing columns.  With that in mind, it's a whole lot easier if you make multiple BCP Format Files to control the Bulk Inserts.  You could even control which format file to use by reading just the first row as a blob, splitting it, and checking which columns aren't there according to sys.columns for the table.

    Shoot, for that matter, you could build the format files on the fly using a similar method just in case you get a surprise.

    p.s.  Don't use the god-forsaken XML format files.  Use the old fashioned ones.  It's a whole lot easier to do and read.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • dallastexas wrote:

    Yes, I was also thinking from a maintenance perspective dynamic would not be the best solution.  Today its 3 missing, it might be 5 in the future so adding the missing field using alter is a quick fix.

    Thank you.

    I guess tend to be a bit heterodoxic when it comes to things in SQL.  For this type of thing, I'd embrace dynamic SQL because it would be "set it and forget it" forever.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff, I have no control over the file that is sent, comes from an external source.  Every month its a different column (or columns) not included.  Also, the same column sometimes are is named differently (although the two different names are at least consistent).  Today I use different BCP; identify the columns structure then use the respective code.  The alter database, add column (or rename column) solution will solve the curve balls thrown at the moment.  If a new curve is thrown (ne column I didn't anticipate), I have a automated reconciliation function that will let me know something happened different.

  • Maybe this and use it as a cursor so I can create the columns that way?

    use tempdb;
    GO

    IF OBJECT_ID('tempdb..#Test2') IS NOT NULL DROP TABLE #Test2
    CREATE TABLE #Test2
    (A int, B int, C int, E int, G int);
    GO

    SELECT * FROM #Test2;

    CREATE TABLE #ColumnNames (columnName CHAR NOT NULL);
    GO
    INSERT INTO #ColumnNames VALUES ('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H');

    /* query for missing columns */
    SELECT columnName FROM #ColumnNames cn
    WHERE NOT EXISTS (
    SELECT 1
    FROM tempdb.sys.columns tsc
    where object_id = object_id('tempdb..#Test2')
    AND tsc.name = cn.columnName );

    Then I could use a simple cursor to loop over those and create the missing columns using that. (Yeah, I know "cursor" is a dirty word, but seems like an easy solution, and I'm looping over column names, not millions of rows of data.)

  • I like the idea of altering the temp file to include missing columns. It's a  simple solution that means the important part, the reads, don't change and you don't get strange edge cases from trying to manage this with dynamic SQL.

    I like the idea of explicitly including NULL, and setting data here, or maybe you have a "Not sent" or some other item so you know that this wasn't in the file this time. That might be important downstream to know this wasn't a null/unknown/blank value v not even sent.

  • Steve,

    Since it's only looking at column names and not rows of data, it seems this could be done easily with a little bit of dynamic SQL (just get a list of missing columns and add them, or do they have to be in sequence?) Or is way harder than it has to be?

    Pieter

Viewing 15 posts - 1 through 15 (of 16 total)

You must be logged in to reply to this topic. Login to reply