Getting column information from system MS SQL Server - sql

When I am using the below SQL statement to retrieve the column information of a SQL Server database. I am getting more columns than there actually are I presume this is because of the system columns that are there also.
SELECT
c.name Field,
t.name Type,
c.Precision,
c.Scale,
c.max_length,
c.is_nullable,
c.collation_name
FROM
sys.columns c
INNER JOIN
sys.types t ON t.system_type_id = c.system_type_id
WHERE
object_id = OBJECT_ID('SOPOrders')
You will see the above query is producing ten Order Memos when in fact their should only be the one the var char I still want to be able to report back the prevision dataype maxlength and the null able factor so what is wrong with the above query please.

There may be a couple of reasons for that. First of all, you are joining types by wrong condition - you should use user_type_id instead of system_type_id on both sides. The latter gives you the underlying built-in type which was used as a basis of a user-defined one. See this query, for example:
select * from sys.types t where t.user_type_id != t.system_type_id;
Another possible thing is that the table has a sparse column set, but I might be wrong here.
And, of course, make sure you are actually querying the information about the right table - always include the schema name qualifier, along with the object name, such as:
WHERE object_id=object_id('dbo.SOPOrders')
Failure to do so will not result in duplication you observe, but following it will save you a lot of time trying to figure out the cause of intermittent inconsistencies, when you will have objects with the same name in different schemas.

Why not using Information_Schema.COLUMNS instead??
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'SOPOrders'
Or try to join on
ON c.user_type_id = t.user_type_id
instead of
ON t.system_type_id=c.system_type_id

Related

Use field values inside a Where statement

I'm currently developing some Quality Checks for a database and we have a table that lists out which columns are Required fields. My question is, would it be possible to use this table to generate a where...is null statement? Example below
select * from Required_Fields_Table
inner join Transaction_Table
on key fields
where (value inside field) is null
Thanks!
edit: this is using Microsoft SQL Server
More Details:
We have a Transactions table, and whether a field in that table is required is different based on the type of user (new, active, pending, etc). We have a table that maps these requirements out (a record for each field/status combination). I was hoping to use that table to run a check to make sure we weren't missing required information.
I'm not sure if I understand your question, but hopefully this will heap... you can use this query to get a list of tables and all fields that are nullable
select o.name TableName, c.name ColumnName
from sys.objects o
inner join sys.columns c on o.object_id = c.object_id
where c.is_nullable = 1 -- 1 for nullable, 0 for not nullable
and o.type = 'u' -- user table
and o.name = '{insert table name here if you wish to refine your search}'
From there you can build up queries for each table with the help of a cursor

Searching for a table based on values contained in the table

I have a table with a reason_id foreign key. I need to map that back to its primary table. I have searched our databases for matching/similar column names but I wasn't able to find the table.
I have a list of values that would be associated with the reason_id. I'd like to search for tables that contain the list I have. Any help would be appreciated.
Here's the query I was running to search for columns:
select
t.name as Table_Name,
SCHEMA_NAME(schema_id) as schema_name,
c.name as Column_Name
from
sys.tables as t
inner join
sys.columns c
on
t.OBJECT_ID = c.OBJECT_ID
where
c.name like '%reason%'
There is no easy way to find the related data in other tables.
I'd try with tools such as ApexSQL Search or SQL Search. Both are free and you won’t go wrong with any of these.
If you want to do it with SQL only then identify all columns in all tables that have the same data type. To do so use sys.columns, sys.types and sys.tables views. Once you find all columns just try start writing queries for each table until you find the right one.
I’d go with something like this
select COUNT(*)
from tableX
where tableX.matchedColumn in
(
-- take 100 or more random rows from the original table
-- if result gives you a number that is near to the number of values listed here then you are most probably on the right track
)

SQL Server Count is slow

Counting tables with large amount of data may be very slow, sometimes it takes minutes; it also may generate deadlock on a busy server. I want to display real values, NOLOCK is not an option.
The servers I use is SQL Server 2005 or 2008 Standard or Enterprise - if it matters.
I can imagine that SQL Server maintains the counts for every table and if there is no WHERE clause I could get that number pretty quickly, right?
For example:
SELECT COUNT(*) FROM myTable
should immediately return with the correct value. Do I need to rely on statistics to be updated?
Very close approximate (ignoring any in-flight transactions) would be:
SELECT SUM(p.rows) FROM sys.partitions AS p
INNER JOIN sys.tables AS t
ON p.[object_id] = t.[object_id]
INNER JOIN sys.schemas AS s
ON s.[schema_id] = t.[schema_id]
WHERE t.name = N'myTable'
AND s.name = N'dbo'
AND p.index_id IN (0,1);
This will return much, much quicker than COUNT(*), and if your table is changing quickly enough, it's not really any less accurate - if your table has changed between when you started your COUNT (and locks were taken) and when it was returned (when locks were released and all the waiting write transactions were now allowed to write to the table), is it that much more valuable? I don't think so.
If you have some subset of the table you want to count (say, WHERE some_column IS NULL), you could create a filtered index on that column, and structure the where clause one way or the other, depending on whether it was the exception or the rule (so create the filtered index on the smaller set). So one of these two indexes:
CREATE INDEX IAmTheException ON dbo.table(some_column)
WHERE some_column IS NULL;
CREATE INDEX IAmTheRule ON dbo.table(some_column)
WHERE some_column IS NOT NULL;
Then you could get the count in a similar way using:
SELECT SUM(p.rows) FROM sys.partitions AS p
INNER JOIN sys.tables AS t
ON p.[object_id] = t.[object_id]
INNER JOIN sys.schemas AS s
ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.indexes AS i
ON p.index_id = i.index_id
WHERE t.name = N'myTable'
AND s.name = N'dbo'
AND i.name = N'IAmTheException' -- or N'IAmTheRule'
AND p.index_id IN (0,1);
And if you want to know the opposite, you just subtract from the first query above.
(How large is "large amount of data"? - should have commented this first, but maybe the exec below helps you out already)
If I run a query on a static (means no one else is annoying with read/write/updates in quite a while so contention is not an issue) table with 200 million rows and COUNT(*) in 15 seconds on my dev machine (oracle).
Considering the pure amount of data, this is still quite fast (at least to me)
As you said NOLOCK is not an option, you could consider
exec sp_spaceused 'myTable'
as well.
But this pins down nearly to the same as NOLOCK (ignoring contention + delete/update afaik)
I've been working with SSMS for well over a decade and only in the past year found out that it can give you this information quickly and easily, thanks to this answer.
Select the "Tables" folder from the database tree (Object Explorer)
Press F7 or select View > Object Explorer Details to open Object Explorer Details view
In this view you can right-click on the column header to select the columns you want to see including table space used, index space used and row count:
Note that the support for this in Azure SQL databases seems a bit spotty at best - my guess is that the queries from SSMS are timing out, so it only returns a handful of tables each refresh, however the highlighted one always seems to be returned.
Count will do either a table scan or an index scan. So for a high number of rows it will be slow. If you do this operation frequently, the best way is to keep the count record in another table.
If however you do not want to do that, you can create a dummy index (that will not be used by your query's) and query it's number of items, something like:
select
row_count
from sys.dm_db_partition_stats as p
inner join sys.indexes as i
on p.index_id = i.index_id
and p.object_id = i.object_id
where i.name = 'your index'
I am suggesting creating a new index, because this one (if it will not be used) will not get locked during other operations.
As Aaron Bertrand said, maintaining the query might be more costly then using an already existing one. So the choice is yours.
If you just need a rough count of number of rows, ie. to make sure a table loaded properly or to make sure the data was not deleted, do the following:
MySQL> connect information_schema;
MySQL> select table_name,table_rows from tables;

Get only table columns with DbConnection.GetSchema method

With C# and SQL Server 2005 and by using DbConnection.GetSchema() method, I want to get all a table's columns (not of views) only. I have found two collection names related to this
Columns that returns table and views' columns
ViewColumns returns all the view's columns
Neither of above two returns table columns only, nor they have any property to filter Table-columns.
Any help is respected.
I don't see any easy way to do this with this particular API you're trying to achieve this with - but why not just use a query like this to get your information?
SELECT
c.name AS 'ColumName',
ty.Name AS 'TypeName',
c.max_length,
c.is_identity,
c.is_nullable,
t.name AS 'TableName'
FROM sys.columns c
INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
INNER JOIN sys.tables t ON c.object_id = t.object_id
Just load that into a SqlCommand and execute it against the open connection you have and read the result into some DataTable or other structure for your use. This gives you only table columns - and all of them.

What is syncobj in SQL Server

When I run this script to search particular text in sys.columns and I get a lot of "dbo.syncobj_0x3934443438443332" like rows.
SELECT c.name, s.name + '.' + o.name
FROM sys.columns c
INNER JOIN sys.objects o ON c.object_id=o.object_id
INNER JOIN sys.schemas s ON o.schema_id=s.schema_id
WHERE c.name LIKE '%text%'
If I get it right, they are replication objects. Is it so? Can i just throw them away from my query just like o.name NOT LIKE '%syncobj%' or there's another way?
Thank you.
I've found a solution. Doesn't know, if it's the best one or not.
SELECT c.name, s.name + '.' + o.name
FROM sys.columns c
INNER JOIN sys.objects o ON c.object_id=o.object_id
INNER JOIN sys.schemas s ON o.schema_id=s.schema_id
WHERE c.name LIKE '%text%' AND o.type = 'U'
The result is fine now. As I said syncobj's are replication objects and they don't have a meaning for us. They're used for replication purposes only.
http://www.developmentnow.com/g/114_2007_12_0_0_443938/syncobj-views.htm
EDIT:
Forgot to add, syncobj's are stored in DB as Views, so if you need list of views, you'll probably need to ignore them as I did in my question.
While checking difference between syncobj's and my views, the only difference is is_ms_shipped column. For syncobj it's 1, for others 0. It means that syncobj views are created by system.
P.S. I'll wait for some time and if nobody gives another answer, I'll accept mine.
When you create a replication that does not include all the fields or other meta data changes from the original table. If you do a generate script from a publication it will show you how it is created (see below). The view provide a object to generate the bcp extracts during the initial snapshots.
Here is an example
-- Adding the article synchronization object exec sp_articleview #publication = N'publication_data', #article = N'tablename',
#view_name = N'syncobj_0x4239373642443436', #filter_clause = N'',
#force_invalidate_snapshot = 1, #force_reinit_subscription = 1 GO
P.S. I recently had a problem when the I dropped replication, it failed to drop these and then you have to manually drop the system views to reuse a replication script. Giving a error message
Msg 2714, Level 16, State 3: There is already an object named
'syncobj_0x3437324238353830' in the database.
Which caused the bcp to fail during the snapshot.