Easiest way to retrieve rows from a table with at least one value in NULL [duplicate] - sql

This question already has answers here:
Is there a quick way to check if ANY column is NULL?
(4 answers)
Closed 7 years ago.
Working with MSSSQL I have a table with more than 20 columns, and I want to retrieve rows which have at least one of the column values in NULL. Which would be the most efficient way, or do you have to write something like this?:
Select * from tableName where col1 is null or col2 is null or col3 is null....
Thank you!

Consider that SQL Server will need to check each column in each row to make the determination (at least until it finds a NULL value in a given column). That means that it's going to be doing a full table scan no matter how you happen to organize your query. So, while there may be "prettier" ways to do your query, when it comes to performance I doubt that you'll find anything that is going to be quicker.
The calculated column that #Denis suggested is an exception, but that's because SQL Server is effectively doing the same work ahead of time (or even a little more work, because now it has to write out to the persisted index). At that point it's a matter of where the performance hit is most important to you - finding these columns, or every time that you write to the table.

The most efficient way is to pre-calculate these values (persisted calculated column) (if this appropriate for your case), then index them and query. Here is the idea behind:
CREATE TABLE #temp
(
col1 int,
col2 int,
col3 int,
col_calculated AS CASE WHEN col1 IS NULL OR col2 IS NULL OR col3 IS NULL THEN 0 ELSE 1 END PERSISTED
);
CREATE INDEX IX_TEMP_COLCALCULATED ON #temp(col_calculated);
INSERT INTO #temp VALUES(1, 2, 3), (5, 6, NULL);
SELECT * FROM #temp WHERE col_calculated = 0;

Related

SQL UPDATE value based on row and column location without ID or key

In SQL (I'm using postgres, but am open to other variations), is it possible to update a value based on a row location and a column name when the table doesn't have unique rows or keys? ...without adding a column that contains unique values?
For example, consider the table:
col1
col2
col3
1
1
1
1
1
1
1
1
1
I would like to update the table based on the row number or numbers. For example, change the values of rows 1 and 3, col2 to 5 like so:
col1
col2
col3
1
5
1
1
1
1
1
5
1
I can start with the example table:
CREATE TABLE test_table (col1 int, col2 int, col3 int);
INSERT INTO test_table (col1, col2, col3) values(1,1,1);
INSERT INTO test_table (col1, col2, col3) values(1,1,1);
INSERT INTO test_table (col1, col2, col3) values(1,1,1);
Now, I could add an additional column, say "id" and simply:
UPDATE test_table SET col2 = 5 WHERE id = 1
UPDATE test_table SET col2 = 5 WHERE id = 3
But can this be done just based on row number?
I can select based on row number using something like:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER() FROM test_table
) as sub
WHERE row_number BETWEEN 1 AND 2
But this doesn't seem to play well with the update function (at least in postgres). Likewise, I have tried using some subsets or common table expressions, but again, I'm running into difficulties with the UPDATE aspect. How can I perform something that accomplishes something like this pseudo code?: UPDATE <my table> SET <col name> = <new value> WHERE row_number = 1 or 3, or... This is trivial other languages like R or python (e.g., using pandas's .iloc function). It would be interesting to know how to do this in SQL.
Edit: in my table example, I should have specified the column types to something like int.
This is one of the many instances where you should embrace the lesser evil that is Surrogate Keys. Whichever table has a primary key of (col1,col2,col3) should have an additional key created by the system, such as an identity or GUID.
You don't specify the data type of (col1,col2,col3), but if for some reason you're allergic to surrogate keys you can embrace the slightly greater evil of a "combined key", where instead of a database-created value your unique key field is derived from some other fields. (In this instance, it'd be something like CONCAT(col1, '-', col2, '-', col3) ).
Should neither of the above be practical, you will be left with the greatest evil of having to manually specify all three columns each time you query a record. Which means that any other object or table which references this one will need to have not one but three distinct fields to identify which record you're talking about.
Ideally, btw, you would have some business key in the actual data which you can guarantee by design will be unique, never-changing, and never-blank. (Or at least changing so infrequently that the db can handle cascade updates reasonably well.)
You may wind up using a surrogate key for performance in such a case anyway, but that's an implementation detail rather than a data modeling requirement.

How to fix Error 213 in SQL Columns that ALL allow null

I am having an issue with an sql query used in job automation
The procedure inserts data from a source table(48 columns) to destination table(49 columns where the 49th/last column is NOT in the source table). But all columns in the destination and source table accept null, so that shouldn't be an issue copying from 48 columns to 49 columns.
It throws this error :
Column name or number of supplied values does not match table definition. [SQLSTATE 21S01] (Error 213). The step failed.
It should just insert null into the 49th column and I have checked the column names and they correspond.
Let's treat this like I can't delete the 49th column.
Please what can I do here?
Accepting NULL doesn't mean you can specify 49 cols and 48 values in the sql INSERT statement. The number of columns and number of values must match exactly. Either drop extra column from INSERT list or add 49th value (NULL I guess) to the values list. In both cases if column is NULLable, it will be set to NULL.
First, if you have code that's not working, you should post it so we can tell for sure what's happening. But I'd be pretty willing to bet you're trying to short cut the process and use something like this:
INSERT tableB
SELECT *
FROM tableA
But the tables don't have the same number of columns, so the SQL Engine doesn't know which source column goes into which destination column. You need to provide an explicit list so it knows which one you intend to ignore:
INSERT tableB
(
col1,
col2,
...
col48
)
SELECT
col1,
col2,
...
col48
FROM tableA;

TSQL Technique for attribute evaluation

I have a table with 20 columns. The first is my primary key. The remaining columns are attributes about the primary key. I need to evaluate each column on a row by row basis. If a attribute column has a value other than null, then do some further processing.
The way I am familiar with doing this in TSQL would be a while to bump through the rows, capture the values from the columns, evaluate the values for further processing.
Does anyone have any better ideas?
You could unpivot the table and filter out things that are not NULL:
select pk, col, val
from (select pk, col, val
from table t
unpivot (val for col in (attr1, attr2, . . . )) as unpivot
) u
where val is not null;
This will provide a list of the columns and associated non-NULL values. Note: it assumes that the types of the attribute columns are all the same.
select PK from table where col1 is not null or col2 is not null or col3 is not null
etc.
I think the best approach would be to first define if any column actually has a null value. For that you could use something like the following;
Select DATALENGTH(null,'Attr1','Attr2') // Add all the colums. This will return null. All of the columns must be the same type.
This will return null. Let's say that you have a while loop(you could use Cursor as well but they are considered slower compared to while loops) that checks each row with against the results of this statement and when you find the result to be null then you could actually check which column is null. This should speed up the process a little bit.
Also, this one looks pretty easy about finding the rows that has null values: https://dba.stackexchange.com/questions/14864/test-if-any-fields-are-null

Partial copy of table and insert values at same time?

So this is going to be an odd question but I'm going to try and explain it as best as I can in order to assist anybody trying to help me here...
I am presented with a situation in which I am trying to copy data from one database to another to similar tables, however there is a slight difference which makes a world of difference. db1.table1 allows null values in col3 and does in fact have a number of rows which have null values but db2.table1 does not allow null values in col3 but I still need to copy the values over. Furthermore, db1.table1.col3 is a GUID while db2.table1.col3 is VARCHAR which is part of the issue. If db1.table1.col3 weren't of type GUID I was simply going to UPDATE the column with the text that I need to insert there that I am going to need in db2.table1.col3.
So, to summarize: I am looking for a way to
INSERT INTO db2.table1 (col1, col2, col3...) SELECT col1, col2, col3... FROM db1.table1 but at places where col3 is null, I need to insert text/varchar so that it's not null.
Is there any simpler way to do this than building a temporary table that anybody knows of?
use COALESCE or ISNULL with the replacement text that you want
for example ISNULL(Col3, 'Sometext')
for a GUID, you can use the NEWID() function since you can't insert regular text into a uniqueidentifier data type
The NEWID() function returns a GUID....for example
SELECT NEWID()
26C064EF-0AB6-4DBE-91B3-C2EE40DE7AD6

How to determine of an SQL table row contains values other than NULL

This is the problem:
I have a table with unknown number of columns. all the columns are real.
Assuming there is only one row in that table, I need a method to determine if there is a value other than NULL in that table/row.
I don't know the number of columns nor their name at run-time (and don't want to use c cursor)
SQL Server 2005
I appreciate your help.
Here's one way - CHECKSUM() returns no value if all values in the row are NULL:
create table #t (col1 real, col2 real, col3 real)
select checksum(*) from #t
if ##rowcount = 0
print 'All values are NULL'
else
print 'Non-NULL value(s) found'
drop table #t
On the other hand, I don't really know if this is what you're doing: a "temporary table built in memory" sounds like something you're managing yourself. With more information about what you're trying to achieve, we might be able to suggest a better solution.
And by the way, there is nothing wrong with a single-row table for storing settings. It has the big advantage that each setting has a separate data type, can have CHECK constraints etc.
Sounds like you're doing some kind of a settings/properties table, based on the fact that you know you only have 1 row in it. This is the wrong way to do it, if you need to have dynamic properties; instead have a table with 2 columns: option and value. Then for each dynamic property, you'll store one row.