views:

75

answers:

6

I have a query with loads of columns. I want to select rows where not all the columns are equal to 0.

select * from table
where 
not
( column1 = 0 and
  column2 = 0 and
  column3 = 0 and
  ...
  column45 = 0)

Is this really the tidiest way to do it?

Supposing I then need to change it to ignore when all columns are 1, or negative.. Its a lot of cut and paste..

A: 

You could add a computed column that does the calculation for you. It is not technically any tidier, except that now when you use it in any query you only have to check the computed column as opposed to repeating the calculation.

CREATE TABLE dbo.foo
(
    col1 INT,
    col2 INT,
    col3 INT,
    all_0 AS
    (
        CONVERT(BIT, CASE 
            WHEN col1 = 0 AND col2 = 0 AND col3 = 0 
            THEN 1 ELSE 0 
        END)
    )
);

You could also do something slightly tidier such as:

WHERE col1 + col2 + col3 = 0 -- or 45, if there are 45 such columns
                             -- and you are looking for each column = 1
Aaron Bertrand
The sum() check doesn't work; I thought about it too, but if one of the columns is non-zero, then the answer won't be zero (unless there are accidentally compensating positive and negative values).
Jonathan Leffler
It could be perfectly valid for one column to be +5 and the other -5, in which case the row needs to be shown.. This might not be accidental..
Mongus Pong
Yeah the addition thing was an afterthought. Would work if the values were more tightly constrained, but in any case most things you're going to check in a WHERE clause could also be checked in a CHECK constraint, so the first part of my answer is still relevant I think.
Aaron Bertrand
+1  A: 

(1) You have the wrong connective in the condition - you need OR and not AND.

With the question amended, the observation above is no longer correct.

(2) If you have 45 columns that you need to filter on, you are going to be hard pressed to do any better than what you have written. Pain though it be...

This observation remains true.

Jonathan Leffler
1. I want rows where it is NOT the case that ALL rows are = 0. It needs to be an AND.. ;-)2. As I am fearing!
Mongus Pong
@Mongus Pong: Well, English and negation does funny stuff. However, the Q asks "I want to select rows where none of the columns are equal to 0", which means I do not want any one of the rows to be zero, or 'every column must be non-zero'. This is different from "it is not the case that all columns are zero" (which is equivalent to 'at least one column is not zero).
Jonathan Leffler
@Mongus Pong: subsidiary questions: are the values ever negative? How big can the values get? You might be able to use a sum or a product of the N columns to establish the required condition. However, you do have to worry about overflow, especially with multiplication.
Jonathan Leffler
@Jonathan Sorry, I got the question wrong. Yes the values can be negative. The values can be theoretically infinite, I am looking largely for a general solution here..
Mongus Pong
+1  A: 

You could parameterize the query and put it in a stored procedure or table-valued function. You'd only need to write the query a fixed number of times (once per operation type) regardless of the value(s) you choose.

create function dbo.fn_notequal_columns
(
    @value int
)
returns table
as
(
    select * from [table]
    where column1 <> @value and column2 <> @value ...
)

select * from dbo.fn_notequal_columns(0)
tvanfosson
A: 

You could use CHECKSUM. However, I don't know the internals of CHECKSUM so can't guarantee it would work over large datasets.

CREATE TABLE dbo.FooBar (
    keyCol int NOT NULL IDENTITY (1, 1),
    col1 int NOT NULL,
    col2 int NOT NULL,
    col3 int NOT NULL
    )

INSERT FooBar (col1, col2, col3)
SELECT -45, 0, 45
UNION ALL
SELECT 0, 23, 0
UNION ALL
SELECT 0, 0, 0
UNION ALL
SELECT 1, 0, 0

SELECT
   CHECKSUM(col1, col2, col3)
FROM
   dbo.FooBar

SELECT
   *
FROM
   dbo.FooBar
WHERE
   CHECKSUM(col1, col2, col3) = 0
gbn
+3  A: 

It appears as though the 45 individual columns have a similar meaning. As such, I would encourage you to properly normalize this table. If you did, the query would be simpler and would likely perform better.

G Mastros
Good point and probably explains why sql hasnt really bothered to come up with a tidy solution for this! However in this case it is a stored procedure which performs a massive query, each column is the result of a complex query.. the results are chucked into a temporary table which is then further processed. I then just need to filter out the rows that arent going to be of interest before returning.
Mongus Pong
A: 

you could create a view of a normalized structure and use that as your source for this query:

SELECT all other fields, 'Column1', COL1 FROM tableName
UNION
SELECT all other fields, 'Column2, COL2 FROM TableName
UNION ...
SELECT all other fields, 'Column45', COL45 FROM tableName

Leslie