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
Related
The case I am trying to solve is this: for every row in a table another row from a second table might exist, so I need all data from the row of the first table and the data from the row of the second table if present.
I know I can use data structures as host variables to gather all data from a row in a table. So, my select is this:
select
t1.*
,t2.*
into
:dst1
,:dst2
from table1 t1
left join table2 t2 on t2.key=t1.key
;
where dst1 and dst2 are data structures respectively like table1 and table2 records' format. Pretty simple.
Now, the point is how to catch null result when a row for that key doesn't exist in the second table. In that case I would like to have the corresponding data structure initialized, but coalesce works on one field at a time and I haven't been able to find another solution.
Is there a way to obtain this result?
Any help would be appreciated!
Thanks
One way to deal with this is to use indicator variables. It looks like this:
dcl-ds hs Qualified;
field1 ...
field2 ...
endds;
dcl-s hsind Int(5) Dim(2);
exec sql
select *
into :hs:hsind
from table
fetch first row only;
Note, there is no comma (,) between :hs and :hsind as this is part of the same variable assignment. :hsind is an indicator variable, and in this case is an array of Int(5) with the same number of elements as the host data structure :hs has fields. The indicator variable will contain a 0 if the value in the associated field in :hs is good, or -1 if it is null. So in our example above: If hs.field1 is good, and hs.field2 is null, then hsind(1) = 0, and hsind(1) = -1. Other values mean other things like data mapping error (-2), or string truncation (positive number with original length of string).
So in your example, use something like this:
select
t1.*
,t2.*
into
:dst1:dst1ind
,:dst2:dst2ind
from table1 t1
left join table2 t2 on t2.key=t1.key
;
Where dst1ind is an array if Int(5) with the same number of elements as dst1 has subfields, similarly for dst2ind. Then after your selection, just check dst2ind(1) >= 0, and you have a good select. Notice that you will need to make sure that select into only returns a single row, or you will get errors about that.
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;
I have a table with a 'user_id' column. Within that same table I have another data field labeled 'GMID'. Within that GMID column there are some fields that are null, the ones that aren't null have values that match the user_id data field within that row. Is there a way to create a script or query that will update all null fields in the GMID column to match the corresponding data values in the user_id row within that row? Are there any best practices I should follow, different approaches? Thanks in advance for anyone that can help.
Of course there is
UPDATE your_table
SET GMID=user_id
WHERE GMID IS NULL
But you even don't need WHERE if GMID always should be same as user_id.
By the way, why do you need two columns with same data in one table?
Another approach would be using the 'coalesce' function. It will return the first non-null value. This approach does not involve data changes on your table. On a query you can 'select coalesce(GMID, user_id) as GMID ...' it will return the first column that is not null.
Documentation for oracle DB:
http://docs.oracle.com/cd/B28359_01/server.111/b28286/functions023.htm
Update: I just reversed the name of the columns inside the coalesce function...
Im trying to build a query that will fetch all changed rows from a source table, comparing it to a target table.
The primary key (its not really defined as a primary key, just what we know identifies an unique row) is a composite that consists of lots of foreign keys. Aproximatly about 15, most of which can have NULL values. For simplicity lets say the primary key consists of these three key columns and have 2 value fields that needs to be compared:
CREATE TABLE SourceTable
(
Key1 int NOT NULL,
Key2 nvarchar(10),
Key3 int,
Value1 nvarchar(255),
Value2 int
)
If Key1 = 1, Key2 = NULL and Key3 = 4. Then I would like to compare it to the row in target that has exactly the same values in the key fields. Including NULL in key 2.
The value fields can also have NULL values.
So whats the best approach to use when designing queries like this where NULL values should be considered as real values and compared?
ISNULL? COALESCE? Intersect?
Any suggestions?
ANSI SQL has the IS [NOT] DISTINCT FROM construct that has not been implemented in SQL Server yet (Connect request).
It is possible to simulate this functionality in SQL Server using EXCEPT/INTERSECT however. Both of these treat NULL as equal in comparisons. You are wanting to find rows where the key columns are the same but the value columns are different. So this should do it.
SELECT *
FROM SourceTable S
JOIN DestinationTable D
ON S.Key1 = D.Key1
/*Join the key columns on equality*/
AND NOT EXISTS (SELECT S.Key2,
S.Key3
EXCEPT
SELECT D.Key2,
D.Key3)
/*and the value columns on unequality*/
AND NOT EXISTS (SELECT S.Value1,
S.Value2
INTERSECT
SELECT D.Value1,
D.Value2)
Nulls don't play nice with foreign keys: changing a null to a value will not (in SQL Server) cause it to cascade when updated.
Best to avoid the null value (and for many other reasons too!) Instead get the DBA to nominate some other 'magic' value of the same data type but outside of the domain type. Examples: DATE: far distant or far future date value. INTEGER: zero or negative value. VARCHAR: value in double-curly braces to denote meta data value e.g. '{{NONE}}', '{{UNKNOWN}}', '{{NA}}', etc then a CHECK constraint to ensure values cannot start/end with double curly braces.
Alternatively, model missing information by absence of a tuple in a relvar (closed world assumption) ;)
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.