SQL Wildcard instead of key in SELECT statement - sql

Can I, in a neat way do:
SELECT *
FROM tablename
WHERE * LIKE '%something%';
Without having to do:
SELECT *
FROM tablename
WHERE ColA LIKE '%something%'
OR ColB LIKE '%something%' ...;
Running SQL Server 2008, I get error:
"Cannot use a CONTAINS or FREETEXT predicate on table or indexed view
'tablename' because it is not full-text indexed.
I don't have full text index :)

To build on #Bob Probst's idea, you might try dynamic SQL like this:
-- Set these!
declare #tableName nvarchar(128)= 'MyTableName'
declare #searchString nvarchar(max)= '%something%'
-- Build SQL query
declare #sql nvarchar(max)
select #sql = isnull(#sql + 'or ', 'select * from ' + #tableName + ' where ' )
+ '[' + column_name + '] like ''' + replace(#searchString, '''', '''''') + ''' '
from information_schema.columns
where table_name = #tableName
-- Could use this where clause for only comparing string fields (or eliminating image and such)
--and data_type in ('varchar', 'char','nvarchar', 'nchar')
-- Run SQL query
print (#sql) -- For debug
exec (#sql)

You could script it like this:
select 'select * from dbo.ACCOUNT_DIMENSION where '
union all
select c.name+' like ''%something%'' or '
from sys.tables t
inner join sys.columns c on (t.object_id=c.object_id)
where t.name = 'ACCOUNT_DIMENSION'
union all
select '1=1'

No. This is not possible. You have to write the fieldnames.

You should be able to use the + sign to bind ColA and ColB together:
SELECT
*
FROM
tablename
WHERE
ColA+ColB Like '%something%'

How's CONTAINS* sound?
Use AdventureWorks2008R2;
GO
SELECT Name, Color FROM Production.Product
WHERE CONTAINS((Name, Color), 'Red');
*This requires fulltext indices

Without a fulltext index the only way to do this dynamically is with a dynamically built statement;
declare #sql varchar(max) = 'select * from tablename where 1=0'
select #sql += ' or ' + quotename(column_name) + ' like ''%something%'''
from information_schema.columns
where TABLE_NAME = 'tablename'
and data_type in ('char', 'varchar', 'nchar', 'nvarchar')
exec(#sql)

Related

Set all integer columns in all tables to 0 where the value is currently null

I'm looking for a way in SQL Server to iteratively run the following query (or to achieve the same result):
UPDATE <table> SET <column> = 0 WHERE <column> IS NULL
I've used the following query to get all the columns of type 'int', but how can I achieve the above requirement?
SELECT table_name, column_name FROM information_schema.columns where data_type = 'int' and table_name not like 'v_%' and table_name not like 'sym_%'
This is reasonably simple with some dynamic sql. I would be EXTREMELY careful doing this on any system and would ask questions about why this is a good idea. I would never do this on my system but the code is actually fairly straight forward.
declare #SQL nvarchar(max) = ''
SELECT #SQL = #SQL + 'Update [' + TABLE_NAME + '] set [' + COLUMN_NAME + '] = 0 where [' + COLUMN_NAME + '] IS NULL;'
FROM information_schema.columns
where data_type = 'int'
and table_name not like 'v_%'
and table_name not like 'sym_%'
select #SQL
--exec sp_executesql #SQL

How to print table columns to use in an INSERT query

I need to run some SQL which will return my columns from a table.
I need to use these columns in an INSERT statement.
I could run:
select *
from information_schema.columns
where table_name = 'tableName'
but I need to print something like this:
[table.custid], [table.address], [table.name]
I thought you may need them to use for example with dynamic sql, you can get the list of column in the format you want as:
DECLARE #ColNames VARCHAR(1000)
SELECT #ColNames = COALESCE(#ColNames+', ', '') + QUOTENAME('tableName.'+NAME,'[')
FROM SYS.COLUMNS
WHERE OBJECT_id = OBJECT_id('tableName')
SELECT #ColNames
Edit summary: adding tablename prefix to columns as wanted in question
Try this
SELECT * FROM SYS.COLUMNS
WHERE object_id = OBJECT_ID('dbo.TableName')
DECLARE #sql as VARCHAR(8000)
SET #sql = ' '
SELECT #sql += '[table.'+[Name] + '],' FROM SYS.COLUMNS
WHERE object_id = OBJECT_ID('dbo.TableName')
PRINT(#sql)

Looping through column names with dynamic SQL

I just came up with an idea for a piece of code to show all the distinct values for each column, and count how many records for each. I want the code to loop through all columns.
Here's what I have so far... I'm new to SQL so bear with the noobness :)
Hard code:
select [Sales Manager], count(*)
from [BT].[dbo].[test]
group by [Sales Manager]
order by 2 desc
Attempt at dynamic SQL:
Declare #sql varchar(max),
#column as varchar(255)
set #column = '[Sales Manager]'
set #sql = 'select ' + #column + ',count(*) from [BT].[dbo].[test] group by ' + #column + 'order by 2 desc'
exec (#sql)
Both of these work fine. How can I make it loop through all columns? I don't mind if I have to hard code the column names and it works its way through subbing in each one for #column.
Does this make sense?
Thanks all!
You can use dynamic SQL and get all the column names for a table. Then build up the script:
Declare #sql varchar(max) = ''
declare #tablename as varchar(255) = 'test'
select #sql = #sql + 'select [' + c.name + '],count(*) as ''' + c.name + ''' from [' + t.name + '] group by [' + c.name + '] order by 2 desc; '
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
EXEC (#sql)
Change #tablename to the name of your table (without the database or schema name).
This is a bit of an XY answer, but if you don't mind hardcoding the column names, I suggest you do just that, and avoid dynamic SQL - and the loop - entirely. Dynamic SQL is generally considered the last resort, opens you up to security issues (SQL injection attacks) if not careful, and can often be slower if queries and execution plans cannot be cached.
If you have a ton of column names you can write a quick piece of code or mail merge in Word to do the substitution for you.
However, as far as how to get column names, assuming this is SQL Server, you can use the following query:
SELECT c.name
FROM sys.columns c
WHERE c.object_id = OBJECT_ID('dbo.test')
Therefore, you can build your dynamic SQL from this query:
SELECT 'select '
+ QUOTENAME(c.name)
+ ',count(*) from [BT].[dbo].[test] group by '
+ QUOTENAME(c.name)
+ 'order by 2 desc'
FROM sys.columns c
WHERE c.object_id = OBJECT_ID('dbo.test')
and loop using a cursor.
Or compile the whole thing together into one batch and execute. Here we use the FOR XML PATH('') trick:
DECLARE #sql VARCHAR(MAX) = (
SELECT ' select ' --note the extra space at the beginning
+ QUOTENAME(c.name)
+ ',count(*) from [BT].[dbo].[test] group by '
+ QUOTENAME(c.name)
+ 'order by 2 desc'
FROM sys.columns c
WHERE c.object_id = OBJECT_ID('dbo.test')
FOR XML PATH('')
)
EXEC(#sql)
Note I am using the built-in QUOTENAME function to escape column names that need escaping.
You want to know the distinct coulmn values in all the columns of the table ? Just replace the table name Employee with your table name in the following code:
declare #SQL nvarchar(max)
set #SQL = ''
;with cols as (
select Table_Schema, Table_Name, Column_Name, Row_Number() over(partition by Table_Schema, Table_Name
order by ORDINAL_POSITION) as RowNum
from INFORMATION_SCHEMA.COLUMNS
)
select #SQL = #SQL + case when RowNum = 1 then '' else ' union all ' end
+ ' select ''' + Column_Name + ''' as Column_Name, count(distinct ' + quotename (Column_Name) + ' ) As DistinctCountValue,
count( '+ quotename (Column_Name) + ') as CountValue FROM ' + quotename (Table_Schema) + '.' + quotename (Table_Name)
from cols
where Table_Name = 'Employee' --print #SQL
execute (#SQL)

sql select with column name like

I have a table with column names a1,a2...,b1.b2....
How can I select all those with column names like a%?
This will get you the list
select * from information_schema.columns
where table_name='table1' and column_name like 'a%'
If you want to use that to construct a query, you could do something like this:
declare #sql nvarchar(max)
set #sql = 'select '
select #sql = #sql + '[' + column_name +'],'
from information_schema.columns
where table_name='table1' and column_name like 'a%'
set #sql = left(#sql,len(#sql)-1) -- remove trailing comma
set #sql = #sql + ' from table1'
exec sp_executesql #sql
Note that the above is written for SQL Server.
You need to use view INFORMATION_SCHEMA.COLUMNS
select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = my_table_name AND COLUMN_NAME like 'a%'
TO inline rows you can use PIVOT and for execution EXEC() function.
This will show you the table name and column name
select table_name,column_name from information_schema.columns
where column_name like '%breakfast%'
SELECT * FROM SysColumns WHERE Name like 'a%'
Will get you a list of columns, you will want to filter more to restrict it to your target table
From there you can construct some ad-hoc sql
Here is a nice way to display the information that you want:
SELECT B.table_catalog as 'Database_Name',
B.table_name as 'Table_Name',
stuff((select ', ' + A.column_name
from INFORMATION_SCHEMA.COLUMNS A
where A.Table_name = B.Table_Name
FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)')
, 1, 2, '') as 'Columns'
FROM INFORMATION_SCHEMA.COLUMNS B
WHERE B.TABLE_NAME like '%%'
AND B.COLUMN_NAME like '%%'
GROUP BY B.Table_Catalog, B.Table_Name
Order by 1 asc
Add anything between either '%%' in the main select to narrow down what tables and/or column names you want.
You cannot with standard SQL. Column names are not treated like data in SQL.
If you use a SQL engine that has, say, meta-data tables storing column names, types, etc. you may select on that table instead.
Blorgbeard had a great answer for SQL server. If you have a MySQL server like mine then the following will allow you to select the information from columns where the name is like some key phrase. You just have to substitute the table name, database name, and keyword.
SET #columnnames = (SELECT concat("`",GROUP_CONCAT(`COLUMN_NAME` SEPARATOR "`, `"),"`")
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`='your_database'
AND `TABLE_NAME`='your_table'
AND COLUMN_NAME LIKE "%keyword%");
SET #burrito = CONCAT("SELECT ",#columnnames," FROM your_table");
PREPARE result FROM #burrito;
EXECUTE result;
Thank you #Blorgbeard for the genious idea.
By the way Blorgbeard's query was not working for me so I edited it:
DECLARE #Table_Name as VARCHAR(50) SET #Table_Name = 'MyTable' -- put here you table name
DECLARE #Column_Like as VARCHAR(20) SET #Column_Like = '%something%' -- put here you element
DECLARE #sql NVARCHAR(MAX) SET #sql = 'select '
SELECT #sql = #sql + '[' + sys.columns.name + '],'
FROM sys.columns
JOIN sys.tables ON sys.columns.object_id = tables.object_id
WHERE sys.columns.name like #Column_Like
and sys.tables.name = #Table_Name
SET #sql = left(#sql,len(#sql)-1) -- remove trailing comma
SET #sql = #sql + ' from ' + #Table_Name
EXEC sp_executesql #sql

Drop all tables whose names begin with a certain string

How can I drop all tables whose names begin with a given string?
I think this can be done with some dynamic SQL and the INFORMATION_SCHEMA tables.
You may need to modify the query to include the owner if there's more than one in the database.
DECLARE #cmd varchar(4000)
DECLARE cmds CURSOR FOR
SELECT 'drop table [' + Table_Name + ']'
FROM INFORMATION_SCHEMA.TABLES
WHERE Table_Name LIKE 'prefix%'
OPEN cmds
WHILE 1 = 1
BEGIN
FETCH cmds INTO #cmd
IF ##fetch_status != 0 BREAK
EXEC(#cmd)
END
CLOSE cmds;
DEALLOCATE cmds
This is cleaner than using a two-step approach of generate script plus run. But one advantage of the script generation is that it gives you the chance to review the entirety of what's going to be run before it's actually run.
I know that if I were going to do this against a production database, I'd be as careful as possible.
Edit Code sample fixed.
SELECT 'DROP TABLE "' + TABLE_NAME + '"'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
This will generate a script.
Adding clause to check existence of table before deleting:
SELECT 'IF OBJECT_ID(''' +TABLE_NAME + ''') IS NOT NULL BEGIN DROP TABLE [' + TABLE_NAME + '] END;'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
This will get you the tables in foreign key order and avoid dropping some of the tables created by SQL Server. The t.Ordinal value will slice the tables into dependency layers.
WITH TablesCTE(SchemaName, TableName, TableID, Ordinal) AS
(
SELECT OBJECT_SCHEMA_NAME(so.object_id) AS SchemaName,
OBJECT_NAME(so.object_id) AS TableName,
so.object_id AS TableID,
0 AS Ordinal
FROM sys.objects AS so
WHERE so.type = 'U'
AND so.is_ms_Shipped = 0
AND OBJECT_NAME(so.object_id)
LIKE 'MyPrefix%'
UNION ALL
SELECT OBJECT_SCHEMA_NAME(so.object_id) AS SchemaName,
OBJECT_NAME(so.object_id) AS TableName,
so.object_id AS TableID,
tt.Ordinal + 1 AS Ordinal
FROM sys.objects AS so
INNER JOIN sys.foreign_keys AS f
ON f.parent_object_id = so.object_id
AND f.parent_object_id != f.referenced_object_id
INNER JOIN TablesCTE AS tt
ON f.referenced_object_id = tt.TableID
WHERE so.type = 'U'
AND so.is_ms_Shipped = 0
AND OBJECT_NAME(so.object_id)
LIKE 'MyPrefix%'
)
SELECT DISTINCT t.Ordinal, t.SchemaName, t.TableName, t.TableID
FROM TablesCTE AS t
INNER JOIN
(
SELECT
itt.SchemaName AS SchemaName,
itt.TableName AS TableName,
itt.TableID AS TableID,
Max(itt.Ordinal) AS Ordinal
FROM TablesCTE AS itt
GROUP BY itt.SchemaName, itt.TableName, itt.TableID
) AS tt
ON t.TableID = tt.TableID
AND t.Ordinal = tt.Ordinal
ORDER BY t.Ordinal DESC, t.TableName ASC
On Oracle XE this works:
SELECT 'DROP TABLE "' || TABLE_NAME || '";'
FROM USER_TABLES
WHERE TABLE_NAME LIKE 'YOURTABLEPREFIX%'
Or if you want to remove the constraints and free up space as well, use this:
SELECT 'DROP TABLE "' || TABLE_NAME || '" cascade constraints PURGE;'
FROM USER_TABLES
WHERE TABLE_NAME LIKE 'YOURTABLEPREFIX%'
Which will generate a bunch of DROP TABLE cascade constraints PURGE statements...
For VIEWS use this:
SELECT 'DROP VIEW "' || VIEW_NAME || '";'
FROM USER_VIEWS
WHERE VIEW_NAME LIKE 'YOURVIEWPREFIX%'
EXEC sp_MSforeachtable 'if PARSENAME("?",1) like ''%CertainString%'' DROP TABLE ?'
Edit:
sp_MSforeachtable is undocumented hence not suitable for production because it's behavior may vary depending on MS_SQL version.
Here is my solution:
SELECT CONCAT('DROP TABLE `', TABLE_NAME,'`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'TABLE_PREFIX_GOES_HERE%';
And of course you need to replace TABLE_PREFIX_GOES_HERE with your prefix.
I saw this post when I was looking for mysql statement to drop all WordPress tables based on #Xenph Yan here is what I did eventually:
SELECT CONCAT( 'DROP TABLE `', TABLE_NAME, '`;' ) AS query
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'wp_%'
this will give you the set of drop queries for all tables begins with wp_
CREATE PROCEDURE usp_GenerateDROP
#Pattern AS varchar(255)
,#PrintQuery AS bit
,#ExecQuery AS bit
AS
BEGIN
DECLARE #sql AS varchar(max)
SELECT #sql = COALESCE(#sql, '') + 'DROP TABLE [' + TABLE_NAME + ']' + CHAR(13) + CHAR(10)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE #Pattern
IF #PrintQuery = 1 PRINT #sql
IF #ExecQuery = 1 EXEC (#sql)
END
Xenph Yan's answer was far cleaner than mine but here is mine all the same.
DECLARE #startStr AS Varchar (20)
SET #startStr = 'tableName'
DECLARE #startStrLen AS int
SELECT #startStrLen = LEN(#startStr)
SELECT 'DROP TABLE ' + name FROM sysobjects
WHERE type = 'U' AND LEFT(name, #startStrLen) = #startStr
Just change tableName to the characters that you want to search with.
This worked for me.
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += '
DROP TABLE '
+ QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ';'
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name LIKE 'something%';
PRINT #sql;
-- EXEC sp_executesql #sql;
select 'DROP TABLE ' + name from sysobjects
where type = 'U' and sysobjects.name like '%test%'
-- Test is the table name
SELECT 'if object_id(''' + TABLE_NAME + ''') is not null begin drop table "' + TABLE_NAME + '" end;'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
I had to do a slight derivation on Xenph Yan's answer I suspect because I had tables not in the default schema.
SELECT 'DROP TABLE Databasename.schema.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'strmatch%'
In case of temporary tables, you might want to try
SELECT 'DROP TABLE "' + t.name + '"'
FROM tempdb.sys.tables t
WHERE t.name LIKE '[prefix]%'
I would like to post my proposal of the solution which DROP (not just generate and select a drop commands) all tables based on the wildcard (e.g. "table_20210114") older than particular amount of days.
DECLARE
#drop_command NVARCHAR(MAX) = '',
#system_time date,
#table_date nvarchar(8),
#older_than int = 7
Set #system_time = (select getdate() - #older_than)
Set #table_date = (SELECT CONVERT(char(8), #system_time, 112))
SELECT #drop_command += N'DROP TABLE ' + QUOTENAME(SCHEMA_NAME(schema_id)) + '.' + QUOTENAME([Name]) + ';'
FROM <your_database_name>.sys.tables
WHERE [Name] LIKE 'table_%' AND RIGHT([Name],8) < #table_date
SELECT #drop_command
EXEC sp_executesql #drop_command
If your query returns more than one line, you can collect the results and merge them into a query.
declare #Tables as nvarchar(max) = '[schemaName].['
select #Tables =#Tables + TABLE_NAME +'],[schemaName].['
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_SCHEMA = 'schemaName'
AND TABLE_NAME like '%whateverYourQueryIs%'
select #Tables = Left(#Tables,LEN(#Tables)-13) --trying to remove last ",[schemaName].[" part, so you need to change this 13 with actual lenght
--print #Tables
declare #Query as nvarchar(max) = 'Drop table ' +#Tables
--print #Query
exec sp_executeSQL #Query
Try following code:
declare #TableLst table(TblNames nvarchar(500))
insert into #TableLst (TblNames)
SELECT 'DROP TABLE [' + Table_Name + ']'
FROM INFORMATION_SCHEMA.TABLES
WHERE Table_Name LIKE 'yourFilter%'
WHILE ((select COUNT(*) as CntTables from #TableLst) > 0)
BEGIN
declare #ForExecCms nvarchar(500) = (select top(1) TblNames from #TableLst)
EXEC(#ForExecCms)
delete from #TableLst where TblNames = #ForExecCms
END
This SQL script is executed without using a cursor.