Should I Type * or 1 With the EXISTS Logical Operator

  • Richard.Bielawski wrote:

    Did you miss a big point?  There is actually a very good reason to name a specific column!

    If you don't have access to every single column in the table then any value except a specific column that you do have access to will cause a security failure.

    All generic values such as *, 1 or null cause all columns to be checked.  If you name a specific column, that's the only column that will be checked.

    This is an interesting point. When using EXISTS the engine only checks for the existence of rows. But what happens if your EXISTS uses * or a column that you don't have access to though column level security.

    _______________________________________________________________

    Need help? Help us help you.

    Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.

    Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.

    Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
    Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
    Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
    Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/

  • There is a good set of stories about the exists () predicate. The first implementations in Oracle actually worked out the SELECT statement without any optimizations. This meant that a "SELECT *" would return all of the columns, clearly a waste of time and space. However, if you used "SELECT <comstant>" the SQL engine did not have to go to the table. This style became part of the folklore long after the optimizers improved.

    Today, we prefer to use "SELECT *" because this is never used as part of the select statement in good programming practice; we really want to see just the columns that we need in the select list. The Asterix tells us we are dealing with the existence of a row as a whole and not a particular set of columns.

    Please post DDL and follow ANSI/ISO standards when asking for help. 

  • Michael L John wrote:

    Richard.Bielawski wrote:

    Did you miss a big point?  There is actually a very good reason to name a specific column!If you don't have access to every single column in the table then any value except a specific column that you do have access to will cause a security failure.All generic values such as *, 1 or null cause all columns to be checked.  If you name a specific column, that's the only column that will be checked.

    In an WHERE EXISTS, the columns do not get checked.  That's kind of the point of this article.

    Sean Lange wrote:

    This is an interesting point. When using EXISTS the engine only checks for the existence of rows. But what happens if your EXISTS uses * or a column that you don't have access to though column level security.

    Michael and Sean (and others): Richard is correct. I am about to post a proof of this along with a slightly different approach to proving that, outside of the permission issue, it doesn't matter what you specify in the SELECT list.

    I will post a link here as soon as I publish it.

    Take care, Solomon..

    SQL#https://SQLsharp.com/ ( SQLCLR library ofover 340 Functions and Procedures)
    Sql Quantum Lifthttps://SqlQuantumLift.com/ ( company )
    Sql Quantum Leaphttps://SqlQuantumLeap.com/ ( blog )
    Info sitesCollations     •     Module Signing     •     SQLCLR

  • OK - I'm missing something or misunderstanding the point, because SELECT 1 or SELECT * works fine for a user that is denied permission on a column within the table used in the EXISTS clause:

    IF NOT EXISTS(SELECT 1 FROM sys.database_principals WHERE name = 'LowPriv')
    BEGIN;
    CREATE USER LowPriv WITHOUT LOGIN;
    END;
    GO

    DROP TABLE IF EXISTS dbo.TestExists;
    GO

    CREATE TABLE dbo.TestExists(
    i int NOT NULL PRIMARY KEY,
    j int NOT NULL
    );
    GO

    INSERT INTO dbo.TestExists(i, j)
    VALUES
    (1, 100),
    (2, 200)
    ;
    GO
    GRANT ALL ON dbo.TestExists TO LowPriv;
    DENY SELECT ON dbo.TestExists(j) TO LowPriv;
    GO


    SELECT 'ABC'
    WHERE EXISTS(
    SELECT i
    FROM dbo.TestExists
    WHERE i = 2
    );
    GO

    -- Works
    EXECUTE AS USER = 'LowPriv';
    SELECT 'ABC'
    WHERE EXISTS(
    SELECT 1
    FROM dbo.TestExists
    WHERE i = 2
    );
    GO
    REVERT;
    GO

    -- Error
    EXECUTE AS USER = 'LowPriv';
    SELECT 'ABC'
    WHERE EXISTS(
    SELECT j
    FROM dbo.TestExists
    WHERE i = 2
    );
    GO
    REVERT;
    GO

    Looking forward to elaboration.

     

  • cs_troyk wrote:

    OK - I'm missing something or misunderstanding the point, because SELECT 1 or SELECT * works fine for a user that is denied permission on a column within the table used in the EXISTS clause:

    -- Works
    EXECUTE AS USER = 'LowPriv';
    SELECT 'ABC'
    WHERE EXISTS(
    SELECT 1
    FROM dbo.TestExists
    WHERE i = 2
    );
    GO
    REVERT;
    GO

     

    Hello. The reason that you see it working is due to the reference of a permitted column in the subquery. In your case, you reference the i column in the WHERE clause. If you remove the WHERE clause and re-execute the query as the LowPriv user, you will get the error. Likewise, if you then add the i column to the SELECT list (e.g. SELECT 1, i ... ) it will again succeed.

     

    I am including this nuance in my post.

     

    Take care,

    Solomon..

     

    SQL#https://SQLsharp.com/ ( SQLCLR library ofover 340 Functions and Procedures)
    Sql Quantum Lifthttps://SqlQuantumLift.com/ ( company )
    Sql Quantum Leaphttps://SqlQuantumLeap.com/ ( blog )
    Info sitesCollations     •     Module Signing     •     SQLCLR

  • Thanks for the additional clarification, Solomon. Very interesting behavior. I don't know, though, that I've constructed many (any) EXISTS predicates that weren't correlated in some way, hence always referencing at least one column from the inner table. I can imagine a scenario, though, perhaps leveraging a "control" table of some kind. I'll definitely keep this issue in mind going forward. Thanks!

  • Solomon Rutzky wrote:

    Michael L John wrote:

    Richard.Bielawski wrote:

    Did you miss a big point?  There is actually a very good reason to name a specific column!If you don't have access to every single column in the table then any value except a specific column that you do have access to will cause a security failure.All generic values such as *, 1 or null cause all columns to be checked.  If you name a specific column, that's the only column that will be checked.

    In an WHERE EXISTS, the columns do not get checked.  That's kind of the point of this article.

    Sean Lange wrote:

    This is an interesting point. When using EXISTS the engine only checks for the existence of rows. But what happens if your EXISTS uses * or a column that you don't have access to though column level security.

    Michael and Sean (and others): Richard is correct. I am about to post a proof of this along with a slightly different approach to proving that, outside of the permission issue, it doesn't matter what you specify in the SELECT list.

    I will post a link here as soon as I publish it.

    Take care, Solomon..

    I know it doesn't matter because it is checking for the existence of rows. I often use the 1/0 example myself as proof for other people. But curious if a row is returned if the only referenced column is one you don't have access to.

    • This reply was modified 4 years, 11 months ago by  Sean Lange.

    _______________________________________________________________

    Need help? Help us help you.

    Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.

    Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.

    Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
    Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
    Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
    Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/

  • Here is my post on this topic:

    Actual Difference Between EXISTS(SELECT 1 …), EXISTS(SELECT * …), and EXISTS(SELECT column …)

     

     

    Take care,

    Solomon..

     

    SQL#https://SQLsharp.com/ ( SQLCLR library ofover 340 Functions and Procedures)
    Sql Quantum Lifthttps://SqlQuantumLift.com/ ( company )
    Sql Quantum Leaphttps://SqlQuantumLeap.com/ ( blog )
    Info sitesCollations     •     Module Signing     •     SQLCLR

  • WHERE EXISTS (SELECT NULL ...) is the semantically correct answer, as we really don't care what we are SELECTing, it is just a mechanism to check for existence.

Viewing 9 posts - 31 through 38 (of 38 total)

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