9
\$\begingroup\$

I have the below code to list all tables which have columns DataAreaId and CountryRegionId. This works, but requires me to change the code in two places if I amend the column list (i.e. both the name in ('DataAreaId','CountryRegionId') code to list the required column names, and also the having COUNT(1) = 2 to match the number of specified columns.

select * 
from sys.tables t 
where object_id in 
(
 select object_id
 from sys.columns c
 where name in ('DataAreaId','CountryRegionId')
 group by object_id
 having COUNT(1) = 2
)
order by Name

I can tweak it to make things more dynamic (i.e. so I only have to define the list of columns; and not have to remember to amend count(1) = 2 to match the number of values as so:

declare @cols table(name sysname) 
insert @cols values('DataAreaId'),('CountryRegionId')
select * 
from sys.tables t 
where object_id in 
(
 select object_id
 from sys.columns c
 where name in (select name from @cols)
 group by object_id
 having COUNT(1) = (select COUNT(distinct name) from @cols)
)
order by Name

But that has a bad smell to it / doesn't look elegant.

Any thoughts on how this could be improved, or is this just one of those scenarios where elegance isn't possible? I'm thinking the seldom used ALL keyword may help somehow; though not sure how.

Vogel612
25.5k7 gold badges59 silver badges141 bronze badges
asked Aug 6, 2015 at 11:56
\$\endgroup\$
0

2 Answers 2

6
\$\begingroup\$

In this case, I would consider using a CTE to contain the columns you are interested in. This saves having to declare the variables, and also saves the inserts, etc. The basic concept is the same as your second query though...

with FindColumns as (
 select 'DataAreaId' as Seek
 UNION
 select 'CountryRegionId' as Seek
), MyTables as (
 select object_id as Tab,
 count(*) as ColCount
 from sys.columns inner join FindColumns on name = Seek
 group by object_id
)
select *
from sys.tables
inner join MyTables on object_id = Tab
where ColCount = (select count(*) from FindColumns)

Note how this is really just a re-expression of your second query using Common Table Expressions

I put that query together on the Stack Exchange data explorer as an example using a couple of different column names.... you can see it working there.

answered Aug 6, 2015 at 14:49
\$\endgroup\$
2
  • \$\begingroup\$ Thanks @rolfl; great suggestion on CTE. FYI: I've tweaked slightly above for a minor performance improvement (on my system) and for a few personal preferences, described in my update notes. \$\endgroup\$ Commented Aug 6, 2015 at 18:58
  • \$\begingroup\$ (amended / added as alternate answer below based on @Vogel612's comment) \$\endgroup\$ Commented Aug 6, 2015 at 23:52
1
\$\begingroup\$

Revised code based on @rolfl's suggestion of using CTE instead of Table Variable:

  • Changed from union to union all; since this improves performance.
  • Changed from union all to values since this gives same performance as union all but gives cleaner entry (i.e. less boilerplate code between each value)
  • Changed from a second CTE to a subquery since this reduced code length / looks cleaner (to me; personal opinion).
  • Changed from inner join to where object_id in to keep results to original query (i.e. only table columns returned; could have done this by select t.*, but this felt cleaner.
;with cols as (select * from (values ('DataAreaId'),('CountryRegionId')) x(name))
select * 
from sys.tables t 
where t.object_id in
(
 select object_id
 from sys.columns c
 inner join cols x
 on x.name = c.name
 group by object_id
 having count(1) = (select count(distinct name) from cols)
) 
order by Name
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.