Metadata about a column in SQL Server 2008 R2? - tsql

I'm trying to figure out a way to store metadata about a column without repeating myself.
I'm currently working on a generic dimension loading SSIS package that will handle all my dimensions. It currently does :
Create a temporary table identical to the given table name in parameters (this is a generic stored procedure that receive the table name as parameter, and then do : select top 0 * into ##[INSERT ORIGINAL TABLE NAME HERE] from [INSERT ORIGINAL TABLE NAME HERE]).
==> Here we insert custom code for this particular dimension that will first query the data from a datasource and get my delta, then transform the data and finally loads it into my temporary table.
Merge the temporary table into my original table with a T-SQL MERGE, taking care of type1 and type2 fields accordingly.
My problem right now is that I have to maintain a table with all the fields in it to store a metadata to tell my scripts if this particular field is type1 or type2... this is nonsense, I can get the same data (minus type1/type2) from sys.columns/sys.types.
I was ultimately thinking about renaming my fields to include their type in it, such as :
FirstName_T2, LastName_T2, Sex_T1 (well, I know this can be type2, let's not fall into that debate here).
What do you guyz would do with that? My solution (using a table with that metadata) is currently in place and working, but it's obvious that repeating myself from the systables to a custom table is nonsense, just for a simple type1/type2 info.
UPDATE: I also thought about creating user defined types like varchar => t1_varchar, t2_varchar, etc. This sounds like something a bit sluggy too...

Everything you need should already be in INFORMATION_SCHEMA.COLUMNS
I can't follow your thinking of not using provided tables/views...
Edit: As scarpacci mentioned, this somewhat portable if needed.

I know this is bad, but I will post an answer to my own question... Thanks to GBN for the help tho!
I am now storing "flags" in the "description" field of my columns. I, for example, can store a flag this way : "TYPE_2_DATA".
Then, I use this query to get the flag back for each and every column :
select columns.name as [column_name]
,types.name as [type_name]
,extended_properties.value as [column_flags]
from sys.columns
inner join sys.types
on columns.system_type_id = types.system_type_id
left join sys.extended_properties
on extended_properties.major_id = columns.object_id
and extended_properties.minor_id = columns.column_id
and extended_properties.name = 'MS_Description'
where object_id = ( select id from sys.sysobjects where name = 'DimDivision' )
and is_identity = 0
order by column_id
Now I can store metadata about columns without having to create a separate table. I use what's already in place and I don't repeat myself. I'm not sure this is the best possible solution yet, but it works and is far better than duplicating information.
In the future, I will be able to use this field to store more metadata, where as : "TYPE_2_DATA|ANOTHER_FLAG|ETC|OH BOY!".
UPDATE :
I now store the information in separate extended properties. You can manage extended properties using sp_addextendedproperty and sp_updateextendedproperty stored procedures. I have created a simple store procedure that help me to update those values regardless if they currently exist or not :
create procedure [dbo].[UpdateSCDType]
#tablename nvarchar(50),
#fieldname nvarchar(50),
#scdtype char(1),
#dbschema nvarchar(25) = 'dbo'
as
begin
declare #already_exists int;
if ( #scdtype = '1' or #scdtype = '2' )
begin
select #already_exists = count(1)
from sys.columns
inner join sys.extended_properties
on extended_properties.major_id = columns.object_id
and extended_properties.minor_id = columns.column_id
and extended_properties.name = 'ScdType'
where object_id = (select sysobjects.id from sys.sysobjects where sysobjects.name = #tablename)
and columns.name = #fieldname
if ( #already_exists = 0 )
begin
exec sys.sp_addextendedproperty
#name = N'Scd_Type',
#value = #scdtype,
#level0type = N'SCHEMA',
#level0name = #dbschema,
#level1type = N'TABLE',
#level1name = #tablename,
#level2type = N'COLUMN',
#level2name = #fieldname
end
else
begin
exec sys.sp_updateextendedproperty
#name = N'Scd_Type',
#value = #scdtype,
#level0type = N'SCHEMA',
#level0name = #dbschema,
#level1type = N'TABLE',
#level1name = #tablename,
#level2type = N'COLUMN',
#level2name = #fieldname
end
end
end
Thanks again

Related

Firebird dynamic Var New and Old

I need validate dynamic Fields from a Table. For example:
CREATE TRIGGER BU_TPROYECTOS FOR TPROYECTOS
BEFORE UPDATE AS
DECLARE VARIABLE vCAMPO VARCHAR(64);
BEGIN
/*In then table "TCAMPOS" are the fields to validate*/
for Select CAMPO from TCAMPOS where TABLA = TPROYECTOS and ACTUALIZA = 'V' into :vCAMPO do
Begin
if (New.:vCAMPO <> Old.:vCampo) then
/*How i get dynamic New.Field1, New.Field2 on query return*/
End;
END ;
The question is : How can I put "The name of the field that the query returns me " in the above code .
Ie if the query returns me the field1 and field5 , I would put the trigger
if ( New.Field1 < > Old.Field1 ) or ( New.Field5 < > Old.Field5 ) then
There is no such feature in Firebird. You will need to create (and preferably) generate triggers that will reference all fields hard coded. If the underlying table changes or the requirements for validation, you will need to recreate the trigger to take the added or removed fields into account.

DB2 Query : insert data in history table if not exists already

I have History table and transaction table.....and reference table...
If status in reference table is CLOSE then take those record verify in History table if not there insert from transaction table..... wiring query like this .... checking better one... please advice.. this query can be used for huge data ?
INSERT INTO LIB1.HIST_TBL
( SELECT R.ACCT, R.STATUS, R.DATE FROM
LIB2.HIST_TBL R JOIN LIB1.REF_TBL C
ON R.ACCT = C.ACCT WHERE C.STATUS = '5'
AND R.ACCT NOT IN
(SELECT ACTNO FROM LIB1.HIST_TBL)) ;
If you're on a current release of DB2 for i, take a look at the MERGE statement
MERGE INTO hist_tbl H
USING (SELECT * FROM ref_tbl R
WHERE r.status = 'S')
ON h.actno = r.actno
WHEN NOT MATCHED THEN
INSERT (actno,histcol2, histcol3) VALUES (r.actno,r.refcol2,r.refcol3)
--if needed
WHEN MATCHED
UPDATE SET (actno,histcol2, histcol3) = (r.actno,r.refcol2,r.refcol3)

update data using loop in sql syntax

I work with postgreSQL
I want to update email of all my users using sql
I have a table named user that contains 500 users,
so I think that I should use a loop in my sql syntax
For example when the table contains 4 users, I want the email for these users to become :
user1#hotmail.fr
user2#hotmail.fr
user3#hotmail.fr
user4#hotmail.fr
in java it should be like this
String newValue=null;
for(int i=0;i<list.size();i++)
{
newValue="user"+i+"#hotmail.fr";
// make update
}
I think that I should use plsql syntax
updated :
I try without success with this code :
BEGIN
FOR r IN SELECT * from user_
LOOP
NEXT r;
UPDATE user_ SET emailaddress = CONCAT('user',r,'#hotmail.fr')
END LOOP;
END
I solved the problem using this query :
UPDATE user_ SET emailaddress='user' || col_serial || '#hotmail.fr' FROM
(SELECT emailaddress, row_number() OVER ( ORDER BY createdate) AS col_serial FROM user_ ORDER BY createdate) AS t1
WHERE user_.emailaddress=t1.emailaddress

splitting a string and rebuilding from related data

I've been given a string that can contain multiple offer codes separated by a tilde 123~125~126
I also have a table that may or may not define a parent/child relationship
tbl_allowed
============
offercode varchar(15)
parent_oc varchar(15)
ex:
offercode = 124
parent_oc = 126
I already have a function that will take the delimited string and split it, but I want to take the string, compare the contents to what's in tbl_allowed and regenerate it by replacing any values that exist in tbl_allowed in the parent_oc column with the value in the offercode column. If no defined relationship exists, then just use itself.
this is pretty simple with a single offercode:
set #newOfferCode = (select top 1 coalesce(cac.offercode, #lOfferCode)
from tbl_allowed cac
where OfferCode = #lOfferCode or parent_oc = #lOfferCode)
select coalesce(nullif(#newOfferCode,''), #lOfferCode)
but I'm having difficulty when I have a tilde delimited string. Any ideas?
Here's what I ended up doing. Seems to work.
CREATE TABLE #tempoffers(OfferCode varchar(15), NewOfferCode varchar(15))
INSERT INTO #tempoffers
SELECT OutParam, null
FROM dbo.SplitString(#lOfferCode, '~')
update #tempoffers set NewOfferCode = coalesce(cac.offercode, mb.offerCode)
from #tempoffers mb
left outer join tbl_Allowed cac on mb.OfferCode = cac.parent_oc
-- building the new string
declare #newOfferCode varchar(5000)
SELECT #newOfferCode = COALESCE(#newOfferCode + '~', '') + NewOfferCode FROM #tempoffers
drop table #tempoffers
SELECT #newOfferCode as OfferCode

How to return text for default language

I have so tables:
and so data at Language table:
and so data at Text table:
I have to return text for requested language if it exists and text for default language if it does not exist. Is it possible to do that in one query (no while, please)?
Code:
DECLARE #CommentId bigint = 1
--DECLARE #LanguageCode nvarchar(2) = 'en' -- "english text" returns
DECLARE #LanguageCode nvarchar(2) = 'ua' -- nothing at this moment
SELECT
t.CommentId
,t.TextId
,t.[Text]
,t.LanguageId
,RequestedLanguageId = #LanguageCode
FROM dbo.common_Text t
INNER JOIN dbo.common_LanguageType l
ON t.LanguageId = l.LanguageId
WHERE l.Code = #LanguageCode
AND t.CommentId = #CommentId
Thank you.
I assume that something is messed up in the data you supplied. Didn't you mean to show a row in the text table with LanguageId = 2? Without using a recursive query or loop, you can't keep following the DefaultId of the language until you end up at English. Assuming there is a row in the text table for ukrainian's backup (2 = russian):
DECLARE
#CommentId BIGINT = 1,
#LanguageCode NVARCHAR(2) = 'ua';
SELECT
CommentId = COALESCE(t.CommentId, a.CommentId),
TextId = COALESCE(t.TextId, a.TextId),
[Text] = COALESCE(t.[Text], a.[Text]),
LanguageId = COALESCE(t.LanguageId, a.LanguageId),
RequestedLanguageId = #LanguageCode
FROM
dbo.common_LanguageType AS l
LEFT OUTER JOIN
dbo.common_Text AS t
ON l.LanguageId = t.LanguageId
AND t.CommentID = #CommentId
LEFT OUTER JOIN
dbo.common_Text AS a -- a for "alternate"
ON l.DefaultId = a.LanguageId
WHERE
l.Code = #LanguageCode
AND a.CommentID = #CommentId;
If this is not the case, you need to make the question more clear. If you have LanguageId 4, 'central ukrainian' with a DefualtId = 3, when that language is requested is the query supposed to check the text table for 4, when it's not found, it checks 4's default (3), when that's not found, it checks 3's default (2), when that's not found, it checks 2's default (1) and finally returns the row for 1? If this is the case you will certainly need a more complicated query (using either a recursive CTE or a loop).
Also for the language code you should probably use NCHAR(2) as opposed to NVARCHAR(2). I hope the column is not nullable and unique.
Solution was found on Database Administrators site