| Author |
Topic |
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-20 : 18:08:45
|
| Hi y'all I'm new to the forums here at sqlteam.I am writing a code generator for work. Nothing fancy, but it needs to convert sqlserver tables to c# classes which will play nice with our proprietary framework. I have almost got this down but I have run into a small problem...when querying the metadata tables in sqlserver I currently do this...ALTER procedure dev_get_column_info as select t_obj.name as [TableName], col.name as [ColumnName], typ.name as [Type], col.length as [Length], col.isnullable as [Nullable], col.colid as [OrdinalPosition], pkc.name as [PKColumnName]from sysobjects t_obj inner join syscolumns col on col.id = t_obj.id inner join systypes typ on typ.xtype = col.xtype left outer join sysindexkeys k on k.id = t_obj.id left outer join syscolumns pkc on ( pkc.id = k.id and pkc.colid = k.colid )where t_obj.xtype = 'U' /*and t_obj.name LIKE 'bk_ac_%'*/order by [TableName], [OrdinalPosition]... which gives me the list of all the column info for all our user tables as well as some basic info on primary keys. the problem I have is that some tables have composite keys, and so when I run this query I only get the name of one of the primary keys on the table. What I would really like (but don't know how to structure) is to do some sort of subselect of all the primary key fields associated with this table, and if the column name for the current column is found in the subselect query then we know that column is a primary key. So the result of my query would be like 'tableName', 'pkID', 'int', '11', 'NULL', '1', 'IS PRI KEY'rather than 'tableName', 'pkID', 'int', '11', 'NULL', '1', 'pkID'which is what I get now, which gets screwed up if the table is a join table with a composite key.Thanks for the help. |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-06-20 : 18:21:52
|
| Not sure what you want. Can you give an example.This will give the PK columns on a table - you can join to this if that's what you need.http://www.nigelrivett.net/ColumnsInPK.html==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-20 : 18:24:40
|
| Thanks for the fast reply. This is akin to what I want, but it doesn't work...ALTER procedure dev_get_column_info as select t_obj.name as [TableName], col.name as [ColumnName], typ.name as [Type], col.length as [Length], col.isnullable as [Nullable], col.colid as [OrdinalPosition], if col.name in ( select pkc.name from sysindexkeys k, syscolumns pkc where pkc.id = k.id and pkc.colid = k.colid and k.id = t_obj.id ) begin select [IsPK] = 1 end else begin select [IsPK] = 0 endfrom sysobjects t_obj inner join syscolumns col on col.id = t_obj.id inner join systypes typ on typ.xtype = col.xtype --left outer join sysindexkeys k on k.id = t_obj.id -- any keys --left outer join syscolumns pkc on ( -- the column info for the key -- pkc.id = k.id -- and pkc.colid = k.colid --)where t_obj.xtype = 'U' /*and t_obj.name LIKE 'bk_ac_%'*/order by [TableName], [OrdinalPosition]GO |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-20 : 18:31:53
|
For the record, I use this to get the Primary keysALTER procedure dev_get_table_primary_key ( @table_name varchar(50)) as select o.name as [tablename], c.* from sysindexkeys k inner join sysobjects o on o.id = k.id inner join syscolumns c on c.id = o.id and c.colid = k.colid where o.xtype = 'U' and o.name = RTRIM(LTRIM(@table_name))GO |
 |
|
|
kselvia
Aged Yak Warrior
526 Posts |
Posted - 2004-06-20 : 21:53:05
|
| Not an answer but a pointer:set statistics profile onsp_MShelpindex tablenameorsp_help tablename those procedures return the metadata. You might look at them to see how they do it. I notice the order (asc/desc) of indexes is also returned so you might need to retrieve that as well. |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-20 : 22:15:56
|
as you say, not really an answer, but I will take a look. What I really need help on is the sql syntax to do something like this... select t_obj.name as [TableName], col.name as [ColumnName], typ.name as [Type], col.length as [Length], col.isnullable as [Nullable], col.colid as [OrdinalPosition], if col.name in ( select pkc.name from sysindexkeys k, syscolumns pkc where pkc.id = k.id and pkc.colid = k.colid and k.id = t_obj.id ) begin select [IsPK] = 1 end else begin select [IsPK] = 0 end from sysobjects t_obj inner join syscolumns col on col.id = t_obj.id inner join systypes typ on typ.xtype = col.xtype where t_obj.xtype = 'U' order by [TableName], [OrdinalPosition] Do I have to replace the if/else construct with a case construct? If so, can I use an 'in (select...' construct as the test for a case? Then use the boolean result to toggle the appropriate column value? |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-06-20 : 22:34:48
|
| Showing code that doesn't giv what you want doesn't really help us to understand what you do want.How about some sample output?One problem might be the code you are using to get the PK - that won't just get the PK but will get other indexes and statistics too.Have a look at sysindexes. sysindexkeys references the columns for all indexes there via indid.I believe status 2048 is for primary keys in sysindexes but that's internal data so it's better to use the information_schema views.If you just want to flag primary key columns then something like select col.COLUMN_NAME, case when c.COLUMN_NAME is not null then 'yes' else 'no' end from INFORMATION_SCHEMA.COLUMNS col left join INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk on col.TABLE_NAME = pk.TABLE_NAME and CONSTRAINT_TYPE = 'PRIMARY KEY' left join INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.TABLE_NAME = pk.TABLE_NAME and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and col.COLUMN_NAME = c.COLUMN_NAME where col.TABLE_NAME = @tbl==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-06-20 : 22:37:22
|
| With the code you have there yes you would have to replace the if with a case.In t-sql if is a control of flow statement and doesn't appear in queries.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2004-06-21 : 00:29:37
|
quote: Originally posted by chacha I am writing a code generator for work. Nothing fancy, but it needs to convert sqlserver tables to c# classes which will play nice with our proprietary framework.
The folk at http://www.ericjsmith.net/codesmith/ may have what you want, or something that you can more easily adapt than making your own. All for free too!Kristen |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-21 : 01:02:41
|
| No, that won't work. Sorry, actually what we are doing is more involved than what I originally let on, I just want to focus on getting what I need out of the sql for now. Suffice it to say, there is no tool available to do what we need. I will have to be custom built. I just want to know how I can use the sysXXX tables to build a query that...- gets the column name, type, maxlength, table name, nullable, ordinal position, whether the column is included in it's parent table's primary key definition, and if so, is it an identity fieldI think my above examples are on the right track. I just don't know how to structure that subselect and the case statement in the select query. For each tuple returned I want to check whether the column name or colid is included in the table's primary key fields, so I can set a bit or flag. |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-21 : 01:19:49
|
I figured it out. This does exactly what I want...select t_obj.name as [TableName], col.name as [ColumnName], typ.name as [Type], col.length as [Length], col.isnullable as [Nullable], col.colid as [OrdinalPosition], CASE WHEN col.name IN( select pkc.name from sysindexkeys k, syscolumns pkc where pkc.id = k.id and pkc.colid = k.colid and k.id = t_obj.id ) THEN 1 ELSE 0 END as [IsPK]from sysobjects t_obj inner join syscolumns col on col.id = t_obj.id inner join systypes typ on typ.xtype = col.xtype --left outer join sysindexkeys k on k.id = t_obj.id -- any keys --left outer join syscolumns pkc on ( -- the column info for the key -- pkc.id = k.id -- and pkc.colid = k.colid --)where t_obj.xtype = 'U' /*and t_obj.name LIKE 'bk_ac_%'*/order by [TableName], [OrdinalPosition] |
 |
|
|
kselvia
Aged Yak Warrior
526 Posts |
Posted - 2004-06-21 : 01:35:24
|
| Yeah sorry, I was just about to post that very thing. We really dropped the ball and over analyzed the question instead of just answering what you asked :( |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-06-21 : 07:40:12
|
| Did you read my post about that not giving PK cols? Don't think it does anyway.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-21 : 13:59:20
|
quote: Originally posted by nr Did you read my post about that not giving PK cols? Don't think it does anyway.
Currently only primary keys are being returned and the results on a complex schema of ~100 tables is perfect. But I think you are right, we just haven't indexed tables yet, b/c there is not data in the tables at this time. But if I really want to make sure that only pk's are returned into the set I could just join sysindexes and sysobjects to sysindexkeys, restricting the join to sysobjects where xtype = 'PK', right? |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2004-06-21 : 14:19:47
|
Sorry, been a bit busy and not enough time to properly understand your issue, but if its any help here's what I use to get "schema" data about a tableUSE NorthwindGO-- SELECT name FROM sysobjects WHERE type = 'U' ORDER BY nameDECLARE @strTable varchar(256)SELECT @strTable = 'Order Details'SELECT C.COLUMN_NAME, C.ORDINAL_POSITION, C.DATA_TYPE, C.CHARACTER_MAXIMUM_LENGTH, C.NUMERIC_PRECISION, C.NUMERIC_SCALE, [PKID] = KCU.ordinal_position, [IsIdentity] = 0, [IsCalculated] = 0, [IsNullable] = 0, [DefaultValue] = CONVERT(varchar(7000), NULL)INTO #TEMP_TABLE_02FROM INFORMATION_SCHEMA.TABLES T JOIN INFORMATION_SCHEMA.COLUMNS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND C.TABLE_SCHEMA = T.TABLE_SCHEMA AND C.TABLE_NAME = T.TABLE_NAME LEFT OUTER JOIN INFORMATION_SCHEMA.table_constraints TC ON TC.TABLE_CATALOG = T.TABLE_CATALOG AND TC.TABLE_SCHEMA = T.TABLE_SCHEMA AND TC.TABLE_NAME = T.TABLE_NAME AND TC.CONSTRAINT_TYPE = 'PRIMARY KEY' LEFT OUTER JOIN INFORMATION_SCHEMA.key_column_usage KCU ON KCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG AND KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME AND KCU.COLUMN_NAME = C.COLUMN_NAMEWHERE T.TABLE_NAME = @strTableORDER BY T.TABLE_NAME, C.ORDINAL_POSITIONUPDATE T1SET [IsIdentity] = CASE WHEN C.colstat = 1 THEN 1 ELSE 0 END, [IsCalculated] = CASE WHEN C.colstat = 4 THEN 1 ELSE 0 END, [IsNullable] = C.isnullable, [DefaultValue] = CONVERT(varchar(7000), COM.[text])FROM #TEMP_TABLE_02 T1 JOIN SYSOBJECTS O ON O.name = @strTable AND O.Type = 'U' JOIN dbo.syscolumns C ON O.id = C.ID AND C.Name = COLUMN_NAME LEFT OUTER JOIN syscomments COM ON COM.ID = C.cdefaultSELECT * FROM #TEMP_TABLE_02 ORDER BY ORDINAL_POSITIONGODROP TABLE #TEMP_TABLE_02GO Sorry if it is answreing the wrong question! I've got one to resolve Foreign Keys somewhere, if you need it.Kristen |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-21 : 16:33:53
|
| That is great Kristen. My code was working properly but your post contains exactly where I was going with this query. I eventually needed the other three key pieces of info you supplied - to know whether the pk columns were identity or not, what the default values for the columns are, and whether the column is calculated or not.Consider this thread resolved. Thanks. |
 |
|
|
chacha
Starting Member
39 Posts |
Posted - 2004-06-21 : 17:29:34
|
for the record, this is what I came up with...select t_obj.name as [TableName], col.name as [ColumnName], CASE WHEN col.name IN( select pkc.name from sysindexkeys k, syscolumns pkc where pkc.id = k.id and pkc.colid = k.colid and k.id = t_obj.id ) THEN 1 ELSE null END as [IsPK], CASE col.colstat WHEN 1 then 1 ELSE 0 END as [IsIdentity], typ.name as [Type], col.length as [Length], col.scale as [Scale], col.prec as [Precision], col.isnullable as [Nullable], col.colid as [OrdinalPosition], col.iscomputed as [IsComputed], com.ctext as [SqlRule]from sysobjects t_obj inner join syscolumns col on col.id = t_obj.id inner join systypes typ on typ.xtype = col.xtype left outer join syscomments com on (com.id = col.id and com.number = col.colid)where t_obj.xtype = 'U' and t_obj.name LIKE 'bk_%'order by [TableName], [OrdinalPosition] |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2004-06-22 : 00:46:27
|
quote: Originally posted by chacha I eventually needed the other three key pieces of info you supplied - to know whether the pk columns were identity or not, what the default values for the columns are, and whether the column is calculated or not
Sounds like you are probably doing exactly what I'm doing with it then! Glad you are now cooking on gas ...Kristen |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-06-22 : 05:21:03
|
quote: Originally posted by chacha
quote: Originally posted by nr Did you read my post about that not giving PK cols? Don't think it does anyway.
Currently only primary keys are being returned and the results on a complex schema of ~100 tables is perfect. But I think you are right, we just haven't indexed tables yet, b/c there is not data in the tables at this time. But if I really want to make sure that only pk's are returned into the set I could just join sysindexes and sysobjects to sysindexkeys, restricting the join to sysobjects where xtype = 'PK', right?
You could do that. As it is you will also get statistics.You could also use he sysindexes status. Note that microsoft are keen for people to use the information schema views where possible as these will be consistent across versions - and in this case it makes the query a lot simpler.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
|