Is there a better way to apply isnull to all columns than what I'm doing? - sql

A number of times over the last month I've had to replace 'null' fields with '0' to every column returned from a query.
to save a lot of time (some of these are returning a high number of columns) I've been using the following and then pasting the results for relevant columns into a new query:
select ', isnull(' + COLUMN_NAME + ', 0)' + ' as ' + COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'summary_by_scca_sales_category '
and TABLE_SCHEMA = 'property''
Essentially I'm wondering if there's a better way that I can do this? Ideally a method where I could automatically apply isnull to all columns being returned in a query (without using two queries).
For example:
I want to take a query like:
select *
from tablename
And for every column returned by * replace null results with 0 without having to write an isnull() line for each column.
edit:
Will accomplish this with a view (doh, should have thought of that). For interests / educations sake is there a way to do something like this with code also?

You could create a VIEW against the tables in question where the ISNULL logic you want is set up. Then queries against the views would return the data you want.
EDIT:
As requested, some sample code to accomplish creating the VIEWs automatically. This is pretty gross, but for something that only has to be run once it will work. Beware of type issues (you stated everything should transmute to 0 so I assume all your columns are of a suitable numeric type):
DECLARE #table_def varchar(max)
SET #table_def = 'CREATE VIEW <tname>_NoNull AS SELECT '
SELECT #table_def = REPLACE(#table_def, '<tname>', t.name) +
'ISNULL(' + c.name + ', 0) AS ' + c.name + ', '
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.name = <<table name>>
SELECT #table_def

Related

Change * in SELECT to show all columns

I'm using SQL Server Management Studio.
Let's say I have a table with 100 fields, and I want to show 75 of them, how can I show all of the columns so then I can just comment out the ones I don't want? Basically de-nest the *...
Thanks!
You can open the columns "folder" under the table in the object explorer and drag the folder to your query window. It will generate the entire list of columns with commas. Not nicely formatted since it drops all the columns on a single line but it works.
You could also use sys.columns to help. This would let you copy and paste the results into your query window.
select name + ', '
from sys.columns
where object_id = object_id('YourTableName')
There are also lots and lots of third party tools that can do this kind of thing.
SSMS support GUI tool for it , but if you don't like GUI then you can use below script
declare
#table_name varchar(200) = 'Employees',
#column_sql varchar(max) = 'select ';
select
#column_sql = #column_sql + 'T.[' + COLUMN_NAME + '],'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME=#table_name;
select left(#column_sql,len(#column_sql)-1) + ' from ' + #table_name + ' T';
In NorthWind Employee Sample will get below result :
select
T.[EmployeeID],T.[LastName],T.[FirstName],T.[Title],
T.[TitleOfCourtesy],T.[BirthDate],T.[HireDate],
T.[Address],T.[City],T.[Region],T.[PostalCode],
T.[Country],T.[HomePhone],T.[Extension],T.[Photo],
T.[Notes],T.[ReportsTo],T.[PhotoPath]
from Employees T

SQL - Search for WHERE clause with no spaces

I am trying to find a performance smart resolution to searching on data that is coming into an application with character spaces removed, but could exist in the DB system in many ways with spaces. I was thinking the following, but it seems to fail:
select top 1 * where REPLACE(Mfr, ' ', '') = #Mfr and REPLACE(Model, ' ', '') = #Model
Am I doing this completely wrong and is there a better way? It appears to time out only only a DB with 150k records at the moment.
You can implement the expressions as indexed virtual columns for fast lookup.
First you'll need to create the virtual columns:
alter table t add clean_mfr as replace(Mfr, ' ', '');
alter table t add clean_model as replace(Model, ' ', '');
Then you'll index them:
create index ix1 on t (clean_mfr, clean_model);
Now, you can try your query again. Since you are using equality (=) in both virtual columns lookups the query should be instantaneous.
Try:
select top 1 *
from t
where REPLACE(Mfr, ' ', '') = #Mfr and REPLACE(Model, ' ', '') = #Model
Or:
select top 1 *
from t
where clean_mfr = #Mfr and clean_model = #Model

How can I exclude GUIDs from a select distinct without listing all other columns in a table?

So let's say 'table' has two columns that act as a GUID - the ID column and msrepl_tran_version. Our original programmer did not know that our replication created this column and included it in a comparison, which has resulted in almost 20,000 records being put into this table, of which only 1,588 are ACTUALLY unique, and it's causing long load times.
I'm looking for a way to exclude the ID and replication columns from a select distinct, without having to then list every single column in the table, since I'm going to have to select from the record set multiple times to fix this (there are other tables affected and the query is going to be ridiculous) I don't want to have to deal with my code being messy if I can help it.
Is there a way to accomplish this without listing all of the other columns?
Select distinct {* except ID, msrepl_tran_version} from table
Other than (where COL_1 is ID and COL_N is the replication GUID)
Select distinct COL_2, ..., COL_N-1, COL_N+1, ... from table
After more searching, I found the answer:
SELECT * INTO #temp FROM table
ALTER TABLE #temp DROP COLUMN id
ALTER TABLE #temp DROP COLUMN msrepl_tran_version
SELECT DISTINCT * FROM #temp
This works for what I need. Thanks for the answers guys!
Absolutely, 100% not possible, there is no subtract columns instruction.
It can't be done in the spirit of the OP's initial question. However, it can be done with dynamic sql:
--Dynamically build list of column names.
DECLARE #ColNames NVARCHAR(MAX) = ''
SELECT #ColNames = #ColNames + '[' + c.COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_SCHEMA = 'dbo'
AND c.TABLE_NAME = 'YourTable'
--Exclude these.
AND c.COLUMN_NAME NOT IN ('ID', 'msrepl_tran_version')
--Keep original column order for appearance, convenience.
ORDER BY c.ORDINAL_POSITION
--Remove trailing comma.
SET #ColNames = LEFT(#ColNames, LEN(#ColNames) - 1)
--Verify query
PRINT ('SELECT DISTINCT ' + #ColNames + ' FROM [dbo].[YourTable]')
--Uncomment when ready to proceed.
--EXEC ('SELECT DISTINCT ' + #ColNames + ' FROM [dbo].[YourTable]')
One additional note: since you need to select from the record set multiple times and potentially join to other tables, you can use the above to create a view on the table. This should make your code fairly clean.

Merge Statement for more than hundreds of columns

I have a Source and Target table that contain more than 150 columns, actually the problem is I need to compare, and insert this 150 column in my MERGE statement, is there any other way to do this?
MERGE targettable AS [Target]
USING (
---Source Query*
) AS [Source] ON [Target].Key = [Source].Key
WHEN MATCHED --Matching records with change //Update
AND [Target].[StartDt] <> [Source].[StartDt]
OR [Target].[ADStatusDesc] <> [Source].[ADStatusDesc]
..... --more than 150 columns
OR [Target].[StatusInd] <> [Source].[StatusInd]
THEN
UPDATE
SET [Target].[StartDt] = [Source].[StartDt]
.... ----more than 150 columns
,[Target].[StatusInd]= [Source].[StatusInd]
Yes, you need to spell them out explicitly. But you can generate that code:
SELECT
col.name
, N' OR NOT(a.' + QUOTENAME(col.name) + N' = b.' + QUOTENAME(col.name) + N' OR (a.' + QUOTENAME(col.name) + N' IS NULL AND b.' + QUOTENAME(col.name) + N' IS NULL))'
FROM sys.columns col
JOIN sys.objects obj ON col.object_id = obj.object_id
JOIN sys.types tp ON col.user_type_id = tp.user_type_id
WHERE obj.name = 'TableNameHere' AND col.is_computed = 0
ORDER BY col.column_id
This properly deals with NULL values as well. For strings, you should probably add collation clauses to use a binary collation.
Are you sure you need to compare all columns on a merge? Can't you simply UPDATE all columns of [Target] with [Source] data whenever [Target].Key = [Source].Key, since [Source] contains the good/new values?
Clever use of text editor features, particularly what's usually called column mode editing, should help you build your SQL statement around a list of column names, one per line (which can be usually extracted from existing SQL statements with even more clever text editing).

How to select some particular columns from a table if the table has more than 100 columns

I need to select 90 columns out of 107 columns from my table.
Is it possible to write select * except( column1,column2,..) from table or any other way to get specific columns only, or I need to write all the 90 columns in select statement?
You could generate the column list:
select name + ', '
from sys.columns
where object_id = object_id('YourTable')
and name not in ('column1', 'column2')
It's possible to do this on the fly with dynamic SQL:
declare #columns varchar(max)
select #columns = case when #columns is null then '' else #columns + ', ' end +
quotename(name)
from sys.columns
where object_id = object_id('YourTable')
and name not in ('column1', 'column2')
declare #query varchar(max)
set #query = 'select ' + #columns + ' from YourTable'
exec (#query)
No, there's no way of doing * EXCEPT some columns. SELECT * itself should rarely, if ever, be used outside of EXISTS tests.
If you're using SSMS, you can drag the "columns" folder (under a table) from the Object Explorer into a query window, and it will insert all of the column names (so you can then go through them and remove the 17 you don't want)
There is no way in SQL to do select everything EXCEPT col1, col2 etc.
The only way to do this is to have your application handle this, and generate the sql query dynamically.
You could potentially do some dynamic sql for this, but it seems like overkill. Also it's generally considered poor practice to use SELECT *... much less SELECT * but not col3, col4, col5 since you won't get consistent results in the case of table changes.
Just use SSMS to script out a select statement and delete the columns you don't need. It should be simple.
No - you need to write all columns you need. You might create an view for that, so your actual statement could use select * (but then you have to list all columns in the view).
Since you should never be using select *, why is this a problem? Just drag the columns over from the Object Explorer and delete the ones you don't want.