FIST_VALUE: Output not as expected

  • I'm trying to find index name based on table_name, column_names, column_position. Tables MN_TST_INDEXES and MN_TST_IND_COLUMNS are used to store existing index details. 
    When trying with below query, I'm unable to get the analytic function FIRST_VALUE work as expected when partitioned by index_name. Please try below code and you'll notice values in FIRST_VAL field is different from the expected output. 
    Can someone please point me what I'm missing here? 

    CREATE TABLE MN_TST_INDEXES(
        INDEX_NAME varchar(30) NOT NULL,
        TABLE_NAME varchar(30) NOT NULL,
        UNIQUENESS varchar(6) NULL,
        ADD_DROP varchar(4) NOT NULL
    )

    CREATE TABLE MN_TST_IND_COLUMNS(
        INDEX_NAME varchar(30) NOT NULL,
        TABLE_NAME varchar(30) NOT NULL,
        COLUMN_NAME varchar(30) NOT NULL,
        COLUMN_POSITION int NOT NULL,
        ADD_DROP varchar(4) NOT NULL
    )

    CREATE TABLE drp_idx_test (col1 INT, col2 INT, col3 INT, col4 INT);
    CREATE INDEX col1_idx ON drp_idx_test(col1);
    CREATE INDEX col2_idx ON drp_idx_test(col2);
    CREATE INDEX col1_col2_idx ON drp_idx_test(col1, col2);
    CREATE INDEX col2_col1_idx ON drp_idx_test(col2, col1);
    CREATE INDEX col1_col2_col3_idx ON drp_idx_test(col1, col2, col3);
    CREATE INDEX col1_col3_col2_idx ON drp_idx_test(col1, col3, col2);
    CREATE INDEX col1_col4_col3_idx ON drp_idx_test(col1, col4, col3);

    INSERT INTO MN_TST_INDEXES (index_name, table_name, uniqueness, add_drop) VALUES ('IDX5', 'DRP_IDX_TEST', NULL, 'DROP');

    INSERT INTO MN_TST_IND_COLUMNS (index_name, table_name, column_name, column_position, add_drop) VALUES ('IDX5', 'DRP_IDX_TEST', 'COL1', 1, 'DROP');
    INSERT INTO MN_TST_IND_COLUMNS (index_name, table_name, column_name, column_position, add_drop) VALUES ('IDX5', 'DRP_IDX_TEST', 'COL3', 2, 'DROP');
    INSERT INTO MN_TST_IND_COLUMNS (index_name, table_name, column_name, column_position, add_drop) VALUES ('IDX5', 'DRP_IDX_TEST', 'COL2', 3, 'DROP');

    ;WITH BASE_IDX ( COLUMN_NAME, COLUMN_POSITION, MAX_POSITION) AS
            (SELECT AIC.COLUMN_NAME, AIC.COLUMN_POSITION, MAX(AIC.COLUMN_POSITION) OVER (PARTITION BY AIC.INDEX_NAME) MAX_POSITION
                FROM MN_TST_IND_COLUMNS AIC
                    WHERE AIC.INDEX_NAME = 'IDX5'
                    AND AIC.ADD_DROP = 'DROP'
            ), USER_IDX ( INDEX_NAME, COLUMN_NAME, COLUMN_POSITION, MAX_POSITION) AS
            (SELECT IND.NAME INDEX_NAME, COL.NAME COLUMN_NAME, INDCOL.INDEX_COLUMN_ID COLUMN_POSITION, MAX(INDCOL.INDEX_COLUMN_ID) OVER (PARTITION BY IND.NAME ) MAX_POSITION
                FROM SYS.INDEXES IND
                    JOIN SYS.INDEX_COLUMNS INDCOL
                        ON INDCOL.OBJECT_ID = IND.OBJECT_ID
                        AND INDCOL.INDEX_ID = IND.INDEX_ID
                    JOIN SYS.COLUMNS COL
                        ON COL.OBJECT_ID = INDCOL.OBJECT_ID
                        AND COL.COLUMN_ID = INDCOL.COLUMN_ID
                    JOIN SYS.TABLES T
                        ON T.OBJECT_ID = IND.OBJECT_ID
                WHERE T.NAME = 'DRP_IDX_TEST'
            ), GET_INDEX_LIST (INDEX_NAME, COLUMN_NAME, COLUMN_ORDER) AS
            (SELECT UI.INDEX_NAME, BI.COLUMN_NAME, (CASE WHEN BI.COLUMN_NAME IS NULL THEN 0 ELSE 1 END) AS COLUMN_ORDER
                FROM BASE_IDX BI
                RIGHT JOIN USER_IDX UI
                    ON UI.COLUMN_NAME = BI.COLUMN_NAME
                    AND UI.COLUMN_POSITION = BI.COLUMN_POSITION
                    AND UI.MAX_POSITION = BI.MAX_POSITION)
                    SELECT INDEX_NAME, COLUMN_NAME, COLUMN_ORDER, FIRST_VALUE(COLUMN_NAME) OVER (PARTITION BY INDEX_NAME ORDER BY COLUMN_ORDER) FIRST_VAL
                FROM GET_INDEX_LIST

    Trying to get output as below:

    INDEX_NAMECOLUMN_NAMECOLUMN_ORDERFIRST_VAL
    col1_col2_col3_idxNULL0NULL
    col1_col2_col3_idxNULL0NULL
    col1_col2_col3_idxCOL11NULL
    col1_col2_idxNULL0NULL
    col1_col2_idxNULL0NULL
    col1_col3_col2_idxCOL11COL1
    col1_col3_col2_idxCOL31COL1
    col1_col3_col2_idxCOL21COL1
    col1_col4_col3_idxNULL0NULL
    col1_col4_col3_idxNULL0NULL
    col1_col4_col3_idxCOL11NULL
    col1_idxNULL0NULL
    col2_col1_idxNULL0NULL
    col2_col1_idxNULL0NULL
    col2_idxNULL0NULL

  • Favor, please.

    Please explain what it is you are trying to accomplish, and then explain why the results of the query are wrong, and how you expect the results that you want.

  • FIRST_VALUE requires a ROWS/RANGE clause.  Since you haven't supplied one, it is using the default ROWS UNBOUNDED PRECEDING.

    FIRST_VALUE returns the first value.  Null is not a value, it's the lack of a value.  Instead of using FIRST_VALUE, you might consider using a CROSS APPLY in conjunction with a TOP (1).

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • drew.allen - Monday, January 23, 2017 1:36 PM

    FIRST_VALUE requires a ROWS/RANGE clause.  Since you haven't supplied one, it is using the default ROWS UNBOUNDED PRECEDING.

    FIRST_VALUE returns the first value.  Null is not a value, it's the lack of a value.  Instead of using FIRST_VALUE, you might consider using a CROSS APPLY in conjunction with a TOP (1).

    Drew

    Thanks Drew, but could you please help me understand why below code works? Below query takes NULL from COL2 when partitioned by COL1 and ordered by COL2

    CREATE TABLE TESTT (COL1 INT, COL2 INT)
    INSERT INTO TESTT VALUES (1, 0)
    INSERT INTO TESTT VALUES (1, 1)
    INSERT INTO TESTT VALUES (1, NULL)
    INSERT INTO TESTT VALUES (1, 3)
    INSERT INTO TESTT VALUES (2, 0)
    INSERT INTO TESTT VALUES (2, NULL)
    INSERT INTO TESTT VALUES (3, 3)
    INSERT INTO TESTT VALUES (3, 1)

    SELECT COL1, COL2, FIRST_VALUE (COL2) OVER (PARTITION BY COL1 ORDER BY COL2) FROM TESTT

  • vpolasa - Monday, January 23, 2017 1:50 PM

    drew.allen - Monday, January 23, 2017 1:36 PM

    FIRST_VALUE requires a ROWS/RANGE clause.  Since you haven't supplied one, it is using the default ROWS UNBOUNDED PRECEDING.

    FIRST_VALUE returns the first value.  Null is not a value, it's the lack of a value.  Instead of using FIRST_VALUE, you might consider using a CROSS APPLY in conjunction with a TOP (1).

    Drew

    Thanks Drew, but could you please help me understand why below code works? Below query takes NULL from COL2 when partitioned by COL1 and ordered by COL2

    CREATE TABLE TESTT (COL1 INT, COL2 INT)
    INSERT INTO TESTT VALUES (1, 0)
    INSERT INTO TESTT VALUES (1, 1)
    INSERT INTO TESTT VALUES (1, NULL)
    INSERT INTO TESTT VALUES (1, 3)
    INSERT INTO TESTT VALUES (2, 0)
    INSERT INTO TESTT VALUES (2, NULL)
    INSERT INTO TESTT VALUES (3, 3)
    INSERT INTO TESTT VALUES (3, 1)

    SELECT COL1, COL2, FIRST_VALUE (COL2) OVER (PARTITION BY COL1 ORDER BY COL2) FROM TESTT

    That does seem odd.  I'm also getting the correct results when I don't use your CTE.


    CREATE TABLE #GET_INDEX_LIST ( [INDEX_NAME] nvarchar(128), [COLUMN_NAME] varchar(30), [COLUMN_ORDER] int )
    INSERT INTO #GET_INDEX_LIST
    VALUES
    ( N'col1_col2_col3_idx', NULL, 0 ),
    ( N'col1_col2_col3_idx', NULL, 0 ),
    ( N'col1_col2_col3_idx', 'COL1', 1 ),
    ( N'col1_col2_idx', NULL, 0 ),
    ( N'col1_col2_idx', NULL, 0 ),
    ( N'col1_col3_col2_idx', 'COL1', 1 ),
    ( N'col1_col3_col2_idx', 'COL3', 1 ),
    ( N'col1_col3_col2_idx', 'COL2', 1 ),
    ( N'col1_col4_col3_idx', NULL, 0 ),
    ( N'col1_col4_col3_idx', NULL, 0 ),
    ( N'col1_col4_col3_idx', 'COL1', 1 ),
    ( N'col1_idx', NULL, 0 ),
    ( N'col2_col1_idx', NULL, 0 ),
    ( N'col2_col1_idx', NULL, 0 ),
    ( N'col2_idx', NULL, 0 )

    SELECT *, FIRST_VALUE(COLUMN_NAME) OVER(PARTITION BY INDEX_NAME ORDER BY COLUMN_ORDER)
    FROM #GET_INDEX_LIST

    DROP TABLE #GET_INDEX_LIST

    You can also use the NULLIF/ISNULL technique to get the results that you are looking for.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • vpolasa - Monday, January 23, 2017 1:50 PM

    Thanks Drew, but could you please help me understand why below code works? Below query takes NULL from COL2 when partitioned by COL1 and ordered by COL2

    CREATE TABLE TESTT (COL1 INT, COL2 INT)
    INSERT INTO TESTT VALUES (1, 0)
    INSERT INTO TESTT VALUES (1, 1)
    INSERT INTO TESTT VALUES (1, NULL)
    INSERT INTO TESTT VALUES (1, 3)
    INSERT INTO TESTT VALUES (2, 0)
    INSERT INTO TESTT VALUES (2, NULL)
    INSERT INTO TESTT VALUES (3, 3)
    INSERT INTO TESTT VALUES (3, 1)

    SELECT COL1, COL2, FIRST_VALUE (COL2) OVER (PARTITION BY COL1 ORDER BY COL2) FROM TESTT

    Define "not working". Your SQL returns what I expect it to.

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

  • drew.allen - Monday, January 23, 2017 2:37 PM

    vpolasa - Monday, January 23, 2017 1:50 PM

    drew.allen - Monday, January 23, 2017 1:36 PM

    FIRST_VALUE requires a ROWS/RANGE clause.  Since you haven't supplied one, it is using the default ROWS UNBOUNDED PRECEDING.

    FIRST_VALUE returns the first value.  Null is not a value, it's the lack of a value.  Instead of using FIRST_VALUE, you might consider using a CROSS APPLY in conjunction with a TOP (1).

    Drew

    Thanks Drew, but could you please help me understand why below code works? Below query takes NULL from COL2 when partitioned by COL1 and ordered by COL2

    CREATE TABLE TESTT (COL1 INT, COL2 INT)
    INSERT INTO TESTT VALUES (1, 0)
    INSERT INTO TESTT VALUES (1, 1)
    INSERT INTO TESTT VALUES (1, NULL)
    INSERT INTO TESTT VALUES (1, 3)
    INSERT INTO TESTT VALUES (2, 0)
    INSERT INTO TESTT VALUES (2, NULL)
    INSERT INTO TESTT VALUES (3, 3)
    INSERT INTO TESTT VALUES (3, 1)

    SELECT COL1, COL2, FIRST_VALUE (COL2) OVER (PARTITION BY COL1 ORDER BY COL2) FROM TESTT

    That does seem odd.  I'm also getting the correct results when I don't use your CTE.


    CREATE TABLE #GET_INDEX_LIST ( [INDEX_NAME] nvarchar(128), [COLUMN_NAME] varchar(30), [COLUMN_ORDER] int )
    INSERT INTO #GET_INDEX_LIST
    VALUES
    ( N'col1_col2_col3_idx', NULL, 0 ),
    ( N'col1_col2_col3_idx', NULL, 0 ),
    ( N'col1_col2_col3_idx', 'COL1', 1 ),
    ( N'col1_col2_idx', NULL, 0 ),
    ( N'col1_col2_idx', NULL, 0 ),
    ( N'col1_col3_col2_idx', 'COL1', 1 ),
    ( N'col1_col3_col2_idx', 'COL3', 1 ),
    ( N'col1_col3_col2_idx', 'COL2', 1 ),
    ( N'col1_col4_col3_idx', NULL, 0 ),
    ( N'col1_col4_col3_idx', NULL, 0 ),
    ( N'col1_col4_col3_idx', 'COL1', 1 ),
    ( N'col1_idx', NULL, 0 ),
    ( N'col2_col1_idx', NULL, 0 ),
    ( N'col2_col1_idx', NULL, 0 ),
    ( N'col2_idx', NULL, 0 )

    SELECT *, FIRST_VALUE(COLUMN_NAME) OVER(PARTITION BY INDEX_NAME ORDER BY COLUMN_ORDER)
    FROM #GET_INDEX_LIST

    DROP TABLE #GET_INDEX_LIST

    You can also use the NULLIF/ISNULL technique to get the results that you are looking for.

    Drew

    Thanks again Drew. I used the case statement (CASE WHEN COLUMN_NAME IS NULL THEN 0 ELSE 1 END) and looks like it's working. But still puzzled why my CTE isn't working for this scenario. 

  • Thom A - Monday, January 23, 2017 2:44 PM

    vpolasa - Monday, January 23, 2017 1:50 PM

    Thanks Drew, but could you please help me understand why below code works? Below query takes NULL from COL2 when partitioned by COL1 and ordered by COL2

    CREATE TABLE TESTT (COL1 INT, COL2 INT)
    INSERT INTO TESTT VALUES (1, 0)
    INSERT INTO TESTT VALUES (1, 1)
    INSERT INTO TESTT VALUES (1, NULL)
    INSERT INTO TESTT VALUES (1, 3)
    INSERT INTO TESTT VALUES (2, 0)
    INSERT INTO TESTT VALUES (2, NULL)
    INSERT INTO TESTT VALUES (3, 3)
    INSERT INTO TESTT VALUES (3, 1)

    SELECT COL1, COL2, FIRST_VALUE (COL2) OVER (PARTITION BY COL1 ORDER BY COL2) FROM TESTT

    Define "not working". Your SQL returns what I expect it to.

    Could you please try the test code I posted in my first post and compare the output with the expected output in the same post? The output values for FIRST_VAL will be different. Please help me understand why we are seeing the output?

Viewing 8 posts - 1 through 7 (of 7 total)

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