Temp tables on the current connection - sql

if I do:
select * from tempdb.sys.tables
I will see all the temporary tables in the system, however that view does not have information about which connection/user each table belongs to. I'm interested in finding only the tables I've created on my current connection. Is there a way to do this?
thanks - e
p.s. yes, I could try reading each table listed with the notion that those that succeed should prove to be mine (on recent versions one can't read other connections' tables) but that is too costly an approach since there may be thousands of tables on the system
p.p.s. I did read Is there a way to get a list of all current temporary tables in SQL Server? which asks the right question but did not get a good answer

Assuming you don't name your #temp tables with three consecutive underscores, this should only pick up your #temp tables. It won't, however, pick up your table variables, nor can you change this code somehow to pick the tables on someone else's connection - this only works because OBJECT_ID('tempdb..#foo') can only return true for a table in your session.
SELECT
name = SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1),
t.[object_id]
FROM tempdb.sys.tables AS t
WHERE t.name LIKE '#%[_][_][_]%'
AND t.[object_id] =
OBJECT_ID('tempdb..' + SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1));
You might also be interested in space used by each of these tables (at least for the heap or clustered index), e.g.:
SELECT
name = SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1),
t.[object_id],
p.used_page_count,
p.row_count
FROM tempdb.sys.tables AS t
INNER JOIN tempdb.sys.dm_db_partition_stats AS p
ON t.[object_id] = p.[object_id]
WHERE t.name LIKE '#%[_][_][_]%'
AND p.index_id IN (0,1)
AND t.[object_id] =
OBJECT_ID('tempdb..' + SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1));
You could extend that to show total space for all indexes. I didn't bother aggregating per partition since these are #temp tables.

select *
from tempdb.sys.objects
where object_id('tempdb.dbo.' + name, 'U') is not null
AND name LIKE '#%'
Would tell you all the tables in tempdb beginning with # that you can access, but Aaron's script just blew me out of the water haha

To find out the name of the user who create the object you just need to check for the schema ID and cross reference with the Schemas table
Select sch.name as 'User Owner' from tempdb.sys.tables TBL
join tempdb.sys.schemas SCH on TBL.schema_id = SCH.schema_id
where TBL.name like '#tmp_Foo%'

Related

Find related columns among hundreds of tables for future relational identification

I am using SQL Server 2016 to pull information out of our ERP system that is stored in a DB2 database. This has thousands of tables with no keys inside of them. When pulling tables from the system, I want to be able to identify matching column names in tables so I can start creating relationships and keys when building dimensions.
Is there a way to create a query that will search my database for column names and list every table that uses that column name? I have been using OPENQUERY and INFORMATION_SCHEMA.TABLES to determine the tables I want to pull over but now I want to start determining relationships between those tables.
Any help would be much appreciated!
You can look in the old yet gold system tables.
A few examples
find all tables with a column named like ID
select so.name, sc.name
from sys.sysobjects so
join sys.syscolumns sc on sc.id = so.id
where so.xtype = N'U'
and sc.name like 'ID%'
Find the FKs from a table
select so2.name
from sys.sysobjects so
join sys.sysforeignkeys fk on so.id = fk.rkeyid
join sys.sysobjects so2 on fk.fkeyid = so2.id
where so.name = 'MyTable'
Check MSDN documentation for further reference and if you want any specific combination just post a new question.
I had to do something similar once, and ended up using something similar to this:
SELECT
T.name
,C1.name
,C2.Name
FROM sys.Tables T
INNER JOIN sys.Columns C1
ON C1.object_id = T.object_id
CROSS APPLY
(
SELECT OBJECT_NAME(CX.object_id) + '.' + CX.Name AS Name
FROM sys.Tables TX
INNER JOIN sys.Columns CX
ON CX.object_id = TX.object_id
AND TX.is_ms_shipped = 0
WHERE CX.object_id <> T.object_id
AND CX.name = C1.name
AND CX.user_type_id = C1.user_type_id
) C2
;
Of course, the problem with any query that we can post here is that it will be extremely generalized, because we aren't familiar with your schema. It's entirely possible, for example, that you will have tables like these:
T_Customers T_Shipments
ID | Name ID | Customer_ID
1 | George 1 | 1
2 | Jane 2 | 1
3 | John 3 | 3
In a case such as that, T_Shipments.Customer_ID should be linked to T_Customers.ID, but won't be in this query, because the name is different.
To search for cases like that, I modified the query later to do a second comparison with concatenations and pattern searches. Not the speediest, but certainly the most thorough - we found all sorts of things we didn't know before. Unfortunately, I can't even begin to guess what your tables/attributes might look like without a lot of further details.
Edit:
Please note that the CROSS APPLY includes a reference to user_type_id, because I wasn't interested at the time in finding columns that had the same name but were a different data type. That might not be the case for you, so you can remove that reference if it isn't relevant.

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;

How can you identify the PK columns in a View

I used to use 'GetSchemaTable' to read schema information, but it was missing some 'stuff', so I wrote a big query, referencing, among other columns, sys.columns,sys.index_columns, and sys.indexes (and other tables) to return the same information I used to get from GetSchemaTable and also return the other pieces of information I want.
Problem is that GetSchemaTable will tell me if a column returned from a view is a Key column from the underlying tables but my new query does not. It'll give me the right answer all day long for tables, but not for views.
Does anyone have a solution to this? I'd hate to have to go back to GetSchemaTable just for that one bit of information, when I'm examing a view. (Plus, I really just want a SQL based solution, ideally.)
Thanks!
Unfortunately in SQL Server 2005 this is not very easy. I have played with this a bit, and it is very close, but it relies on the fact that you name your columns in your view exactly the same as they are named in the base table. This is because the now-deprecated-in-SQL-Server-2008 view sys.sql_dependencies does not properly store the referencing column_id, so there is no way to match this up with the actual columns in the view. I think SQL Server 2008 will have better options for you as they have yet again introduced a new set of dependency objects. I also didn't chase down any paths with INFORMATION_SCHEMA.KEY_COLUMN_USAGE but since these views rely solely on names and not id's of any kind you are likely in the same pickle there. So maybe this can be a start for you but like I said this will only cover the simple cases. If you alias your columns you will be out of luck. Maybe someone else with some insight into the intricacies of how these things are referenced will pull a rabbit out and figure out how to reference mismatched columns...
-- very simple; one-column key:
CREATE TABLE dbo.boo
(
far INT PRIMARY KEY
);
GO
CREATE VIEW dbo.view_boo
AS
SELECT far FROM dbo.boo;
GO
-- slightly more complex. Two-column key,
-- not all columns are in key, view columns
-- are in different order:
CREATE TABLE dbo.foo
(
splunge INT,
a INT,
mort INT,
PRIMARY KEY(splunge, mort)
);
GO
CREATE VIEW dbo.view_foo
AS
SELECT
splunge,
mort,
a
FROM
dbo.foo;
GO
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(v.[object_id])) + '.'
+ QUOTENAME(v.name) + '.' + QUOTENAME(vc.name)
+ ' references '
+ QUOTENAME(OBJECT_SCHEMA_NAME(t.[object_id]))
+ '.' + QUOTENAME(t.name) + '.' + QUOTENAME(tc.name)
FROM
sys.views AS v
INNER JOIN
sys.sql_dependencies AS d
ON v.[object_id] = d.[object_id]
INNER JOIN
sys.tables AS t
ON d.referenced_major_id = t.[object_id]
INNER JOIN
sys.columns AS tc
ON tc.[object_id] = t.[object_id]
INNER JOIN
sys.index_columns AS ic
ON tc.[object_id] = ic.[object_id]
AND tc.column_id = ic.column_id
AND tc.column_id = d.referenced_minor_id
INNER JOIN
sys.columns AS vc
ON vc.[object_id] = v.[object_id]
AND vc.name = tc.name -- the part I don't like
INNER JOIN
sys.indexes AS i
ON ic.[object_id] = i.[object_id]
AND i.is_primary_key = 1
ORDER BY
t.name,
ic.key_ordinal;
GO
DROP VIEW dbo.view_boo, dbo.view_foo;
DROP TABLE dbo.foo, dbo.boo;

Easy way to find out how many rows in total are stored within SQL Server Database?

I'm looking for easy way to count all rows within one SQL Server 2005/2008 database (skipping the system tables of course)? I know i could use
SELECT COUNT (COLUMN) FROM TABLE
and do it for each table and then add it up but would prefer some automated way?
Is there one?
SELECT SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE index_id IN (0,1)
AND OBJECTPROPERTY([object_id], 'IsMsShipped') = 0;
This will be accurate except for, potentially, any rows that are being added or removed within a transaction at the time you run the query. And it won't have the expense of hitting individual tables.
But as I mentioned in another comment, I'm not sure how this helps you determine "how much data" your database holds. How many rows, sure, but if I have 10 glasses, each half full of water, and you have 5 glasses, each completely full, which of us has more water?
This was my answer to a similar question today:
SQL Server 2005 or later gives quite a useful report showing table sizes - including row counts etc. It's in Standard Reports - and it is Disc Usage by Table.
Programmatically, there's a nice solution at: http://www.sqlservercentral.com/articles/T-SQL/67624/
Try:
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects AS so,
sysindexes AS si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
ORDER BY
2 DESC
This is the indexed rows. This is probably only an approximation, as databases change a lot and some stuff might not be indexed, but this will be fast.
EDIT: Note that so.xtype is user types, making the assumption you do not want the system stuff and only "real" data stuff.
EDIT2: no flames note: probably a bad idea to query on the sysobjects table :).
EDIT3: to specifically address requirement, and no associative joins :)
SELECT sum(mycount) from
(SELECT
MAX(si.rows) AS mycount
FROM
sysobjects AS so
join sysindexes AS si on si.id = OBJECT_ID(so.name)
WHERE
so.xtype = 'U'
GROUP BY
so.name
) as mylist
We know that sp_spaceused, when passed a table name, will return a row count, so we can examine what it does - it queries sys.dm_db_partition_stats - and copy it to get this:
SELECT
SUM(ddps.row_count) TotalRows
FROM
sys.indexes i
INNER JOIN sys.objects o ON i.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.dm_db_partition_stats ddps ON
o.OBJECT_ID = ddps.OBJECT_ID
AND i.index_id = ddps.index_id
WHERE
i.index_id < 2
AND o.is_ms_shipped = 0 -- to exclude system tables
Curious requirement though, I have to say...
You could query sysindexes, look at the rowcnt value for the clustered index on each table. But I'm not sure exactly how up to date that is.
Alternatively, something like this (briefly tested on a small test db):
CREATE TABLE #TableRowCount (TableName NVARCHAR(128), RowCnt BIGINT)
INSERT #TableRowCount (TableName, RowCnt)
EXECUTE sp_msforeachtable 'SELECT "?", COUNT(*) FROM ?'
SELECT SUM(RowCnt) AS TotalRowCount FROM #TableRowCount
DROP TABLE #TableRowCount
Check out the undocumented stored procedure sp_MSForEachTable. Using it you can run a Count(*) on every table in the database. For your specific issue:
EXEC sp_MSforeachtable 'SELECT ''?'', Count(*) as NumberOfRows FROM ?'
I'm not sure if older version of MS SQL has the information_shema SQL standard for data dictionary.
You can do something like:
SELECT SUM(table_rows)
FROM information_schema.tables
WHERE table_schema = 'DATABASENAME'