Query to count number of columns in a Sql Server View - sql-server

Like we had query to find no of columns in a Table, is there any similar query to find total no of columns in a Sql Server View ?

Even simpler is to use sys.columns.
select count(*)
from sys.columns
where OBJECT_ID = OBJECT_ID('YourView')

Similar to Larnu's comment, I tend to prefer the Table-Valued-Function
Example
Declare #tsql nvarchar(max) = N'Select * from YourView_Table_Or_Query'
Select column_ordinal
,name
,system_type_name
From sys.dm_exec_describe_first_result_set(#tsql,null,null )
-- Or for the Count
Select ColumnCnt=count(*)
From sys.dm_exec_describe_first_result_set(#tsql,null,null)

Besides the rather clumsy procedure sp_describe_first_reuslt_set you can use the generic abilities of XML:
SELECT (SELECT TOP 1 * FROM YourView FOR XML RAW, ELEMENTS XSINIL ,TYPE).value('count(/row/*)','int');
Edit: Forgot to add ELEMENTS XSNIL which would omit columns with a value of NULL otherwise...

--this might help
SELECT v.name, count(1) ColumnCount
FROM SYS.VIEWS v
INNER JOIN SYS.all_columns c ON v.object_id = c.object_id
WHERE v.name IN (SELECT name FROM sys.VIEWS)
GROUP BY v.name
ORDER BY v.name
SELECT name
FROM sys.VIEWS, can be replaced by viewname/s or query which returns viewname/s

Related

Is there a way to search all SQL tables by column name?

In this answer, you can search all tables for a column by column name.
Say I have a list of columns like this:
DECLARE #columnNames TABLE (Id varchar(30))
INSERT INTO #columnNames
VALUES ('xColumn1Name'), ('xColumn2Name'), ('xColumn3Name')
I want to find all tables that have at least these three columns. Is it possible to do a foreach loop with the code below, or is there a simpler way?
SELECT
COLUMN_NAME AS 'ColumnName', -- this code will get all tables with a column by name #xColumnName, but I would like to pass in a list
TABLE_NAME AS 'TableName'
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME LIKE '#xColumnName'
ORDER BY
TableName, ColumnName;
The table must have all 3 colums named in the list, and it would be cool if I could filter out tables that do not have a certain column or list of columns
This is a relational division question. There are a few methods to solve this as Joe Celko writes. The common solution is as follows:
DECLARE #columnNames TABLE (Id varchar(30))
INSERT INTO #columnNames
VALUES ('xColumn1Name'), ('xColumn2Name'), ('xColumn3Name')
select t.name
from sys.tables t
join sys.columns c on c.object_id = t.object_id
join #columnNames cn on cn.Id = c.name
group by t.object_id, t.name
having count(*) >=
(select count(*) from #columnNames);
What this says is: give me all tables, where the number of columns which match the list #columnName is the same or more as the number in that list, in other words tehre is a match for every column.
This should get your initial goal.
SELECT
[TableName]
FROM (
SELECT
COLUMN_NAME AS 'ColumnName', -- this code will get all tables with a column by name #xColumnName, but I would like to pass in a list
TABLE_NAME AS 'TableName',
ROW_NUMBER() OVER(PARTITION BY TABLE_NAME ORDER BY COLUMN_NAME) rn
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME IN ('xColumn1Name', 'xColumn2Name', 'xColumn3Name')
) a
WHERE rn >= 3
For a short explanation, this query will look through the information schema to find any of these columns in a table. The ROW_NUMBER() then basically groups the columns by table. If there are 3 or more results (rn) then all 3 columns are there.
Since it is a sub select, you can also filter the outside select for particular columns if you want.
You could use INTERSECT to combine different result sets. This will give the records that are in all result sets, so in this case, the tables that have all three columns.
SELECT OBJECT_NAME(object_id) AS Table
FROM sys.columns
WHERE name = 'xColumn1Name'
INTERSECT
SELECT OBJECT_NAME(object_id) AS Table
FROM sys.columns
WHERE name = 'xColumn3Name'
INTERSECT
SELECT OBJECT_NAME(object_id) AS Table
FROM sys.columns
WHERE name = 'xColumn3Name'

Select field_name base on the table id from each of the list

I have a problem.
I want to show field_name at my query 'select .. from .. where' clause.
In my logging table, the table only keep the [date],[table_id],[field_id] .. fields, i need to show the 'field_name' as well in my select but there is no any other table that i can 'join' to get the [field_name] based on [field_id] in my 'select .. from'. As I search from google it seems I can get the field_name from SQL system called 'sys.columns' table. but that is too complicated for my SQL level because this sys.coloums is not straight forward. it mixed all the table before all each field number depend on the table id itself.
anyone who know how to write a good query to select out the field_name pls help :)
log_list table
[date],[table_id],[field_id],[company_name],...
my current query :
SELECT
date , table_id , name as table_name
FROM
log_list join table_name_list on log_list.table_id = table_name_list.table_id
and log_list.company_name like '%something%'
WHERE
date between #startdate and #enddate
thank you for your attention.
Your tag didn't say what version of SQL Server you are using, assuming you are using 2008+ there is a system function
COL_NAME ( table_id , column_id )
which if you supply table_id and column_id would get you the name, for detailed reference check it out here: COL_NAME (Transact-SQL)
If that is not a valid option for you, look closer to sys.columns, the object_id it returns is actually the table's object_id and should be your table_id, so if you do something like following it should work:
select C.name AS column_name
...
FROM ...
...
join sys.columns C on yourtable.table_id = C.object_id and yourtable.column_id = C.column_id

Find a value from certain columns within all tables in a database - dynamic sql?

Is there a way to do this with t-sql without using a cursor or a loop or temporary tables? Maybe by using dynamic sql?
I want to get the maximum value from the first column of each table in a database.
I use syscolumns to show me the names of all the tables and the name of the first column in each table.
So in the (non-working) example below I need to find a way to loop through syscolumns and use all the values for #tabname and #colname. Is there a way of doing that?
declare #tabname sysname;
declare #colname sysname;
SELECT
name as [column name],
object_NAME(id) as [table name],
(select max(#colname) from #tabname) as [max col value]
from syscolumns
where colorder = 1
Any help or tips appreciated.
Regards, Dave.
You can use query like this
;WITH cte
AS (SELECT
object_id,
MIN(column_id) mincolumnid
FROM sys.columns
GROUP BY object_id)
SELECT
t.name,
c.name
FROM sys.tables t
INNER JOIN sys.columns c
ON t.object_id = c.object_id
INNER JOIN cte ct
ON c.object_id = ct.object_id
AND c.column_id = ct.mincolumnid

How to list all the user tables in Sybase along with their row count?

I would like to return all the tables and its count next to it. what is the quickest way to go about it?
I know in Oracle, you can do something like below, but not sure about Sybase:
declare n number;
begin
for rec in (select object_name from user_objects where object_type='TABLE')
loop
execute immediate 'select count(*) from '||rec.object_name into n;
dbms_output.put_line (rec.object_name||':'||n);
end loop;
end;
Here is the Sybase sql that does the above:
select ob.name,st.rowcnt
from sysobjects ob, systabstats st
where ob.type="U"
and st.id=ob.id
order by ob.name
It depends on what Sybase product you mean. In my SQL Anywhere (9 and 11), your solution doesn't work, but this works:
select table_name, count
from systable
where primary_root<>0 and creator=1
order by 1
As there can be multiple entries in systabstats table, the query should be:
select ob.name, sum(st.rowcnt)
from sysobjects ob, systabstats st
where ob.type="U"
and st.id=ob.id
group by ob.name
order by ob.name
If the current user is the creator:
SELECT table_name, count
FROM sys.systable
WHERE creator = user_id()
NOTE: I test this in Sybase ASA 9.
use the below query
select name,row_count(db_id(),id) as "Rows"
from sysobjects where type='U' order by 2 desc
This works for me using "SQL Central" with SQL Anywhere 17:
SELECT table_name, st.count
FROM systable st
WHERE table_type = 'BASE'
select ob.name,st.rowcnt from sysobjects ob, systabstats st where b.type='U'
and st.id=ob.id and indid=0 order by ob.name

T-SQL: Conditionally joining using a parameter

Consider a simple join:
Select TableB.*
From TableA
Inner Join TableB
On TableB.ID = TableA.ID
What I want to do is decide which table to join to depending on a parameter. Although the following syntax is not valid, I wrote it just to illustrate what I am after:
Select TableD.*
From TableA
Inner Join
[If #useTableC = 1 Then Join to TableC Else Join to TableB] As TableD
Both TableB and TableC have identical columns.
How can I create this kind of join. Please be aware that this example is actually a small portion of a much larger query so you cannot just use If...Else statements.
Thanks a lot!
Usually I'd prefer to rewrite in more than one statement, but if you really need it:
SELECT td.*
FROM TableA ta
JOIN (
SELECT tc.* FROM TableC Where #useTableC = 1
UNION ALL
SELECT tb.* FROM TableB Where #useTableC = 0
) td ON ( /* JOIN CONDITION MISSING */)
Unfortunately, T-SQL has no syntax to support this. I tinkered with this some time ago and couldn't come up with a solution, until I found this article that helped me (by using Left Outer joins) and it might help you. It is located here.
#Gerardo Lima's answer is excellent, but as an alternative you could build up your query with dynamic SQL. This would let you use a series of if statements to add, or not, as many joins as you wish using as many if statements as needed. As a coarse and rough example:
declare #sql varchar(8000)
set #sql = 'Select TableD.* From TableA '
if #usertableC = 1
then select #sql = #sql + ' innner join tableC'
if #usertableC != 1
then select #sql = #sql + ' innner join tableB
exec #sql
There is a good discussion of dynamic sql at "the curse and blessing of dynamic sql"
Nice solution, Geraldo! There is not be a performance hit on using the union. I can't tell you why (perhaps someone can fill in the gaps here), but the execution plan shows 0 I/O cost for the constant scan.
However, this does approach depend on the schemas for TableB and TableC being identical. To do this with multiple statements, supporting disparate schemas in TableB and TableC, I'd consider the following approach:
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT td.* FROM TableA ta INNER JOIN Table' +
CASE WHEN #useTableC = 1 THEN 'C' ELSE 'B' END + ' td ON ta.ID = td.ID'
EXEC sp_executesql #sql
Note that it would then be up to your application code to determine the corresponding schema and read the data accordingly.

Resources