23 Kasım 2008 Pazar

SQL SERVER - Tek insert into ile birden fazla kayıt girebilmek - UNION ALL kullanımı

Ref:http://blog.sqlauthority.com/2007/06/08/sql-server-insert-multiple-records-using-one-insert-statement-use-of-union-all/

UNION
UNION ilişkili tabloların aynı tipte verileri olması kaydıyla DISTINCT ile getirmesidir. JOIN lemesi gibi.

UNION ALL
UNION ALL, UNION komutuna eşittir bir farkla, o da tüm değerleri seçmesi.

Union all çiftlenmiş kayıtlarıda getirir. Tüm kayıtlarını getirir ve tablolarını birleştirir.

A UNION komutu SELECT DISTINCT sonucunu getirir. Eğer tüm satırların eşsiz olarak ayrıştığını biliyorsanız UNION ALL kullanın, çünkü daha hızlıdır.

Örneğin:
Table 1 : First,Second,Third,Fourth,Fifth
Table 2 : First,Second,Fifth,Sixth

Result Set:
UNION: First,Second,Third,Fourth,Fifth,Sixth (This will remove duplicate values)
UNION ALL: First,First,Second,Second,Third,Fourth,Fifth,Fifth,Sixth,Sixth (This will repeat values)


USE YourDB
GO
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('First',1);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Second',2);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Third',3);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Fourth',4);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Fifth',5);
GO


yerine

USE YourDB
GO
INSERT INTO MyTable  (FirstColSecondCol)
    
SELECT  'First' ,1
    
UNION ALL
SELECT  'Second' ,2
    
UNION ALL
SELECT  'Third' ,3
    
UNION ALL
SELECT  'Fourth' ,4
    
UNION ALL
SELECT  'Fifth' ,5
GO


sonuç:
INSERT : 5 saniye
INSERT SELECT UNION ALL : 40 milisaniye

SELECT INTO

Ref:reference

USE YourDB
GO
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('First',1);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Second',2);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Third',3);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Fourth',4);
INSERT INTO MyTable  (FirstColSecondCol)
        
VALUES ('Fifth',5);
GO

INSERT INTO SELECT

Ref: http://blog.sqlauthority.com/2007/06/08/sql-server-insert-multiple-records-using-one-insert-statement-use-of-union-all/

USE AdventureWorks
GO
    
----Create TestTable
CREATE TABLE TestTable (FirstName VARCHAR(100), LastName VARCHAR(100))
    
----INSERT INTO TestTable using SELECT
INSERT INTO TestTable (FirstNameLastName)
    
SELECT FirstNameLastName
    
FROM Person.Contact
    
WHERE EmailPromotion 2
    
----Verify that Data in TestTable
SELECT FirstNameLastName
    
FROM TestTable
    
----Clean Up Database
DROP TABLE TestTable
GO

30 Ekim 2008 Perşembe

Cannot resolve the collation conflict between “SQL_Latin1_General_CP1254_CI_AS” and “Turkish_CS_AI” in the equal to operation


ALTER DATABASE kanTahlilleri_new COLLATE SQL_Latin1_General_CP1254_CI_AS

Kaynak: http://www.ahmetkaymaz.com/2006/12/29/sql-serverde-language-ve-collation-kavrami/

select ilce.Ilce_text+‘/’+Il.Il_text
from Il_kodlarI Il
left join Ilce_kodu ilce on ilce.Il_kodu = Il.Il_kodu
collate Turkish_CS_AI

23 Ekim 2008 Perşembe

MSSQL 2005 Hata Yakalama TRY CATCH

BEGIN TRY

select 1/0

END TRY
BEGIN CATCH

-- Hatayı görüntüleyelim
SELECT
ERROR_NUMBER() AS HATANUMARASI
,ERROR_MESSAGE() AS HATAMESAJ
,ERROR_SEVERITY() AS ONEM
,ERROR_STATE() AS DURUM

-- Hatayı tabloya yazalım
INSERT INTO Errors
SELECT ERROR_NUMBER()
,ERROR_MESSAGE()
,ERROR_STATE()
,ERROR_SEVERITY()

END CATCH


ERROR_NUMBER() : Oluşan hatanın kodunu verir
ERROR_MESSAGE() : Oluşan hatanın tam metnini verir. Bu hata mesajı hatanın parametreleri, açıklaması, zamanlaması gibi bilgileri içerir.
ERROR_SEVERITY() : Hatanın önem derecesini bildirir
ERROR_STATE() : Hatanın durum numarasını döndürür.
ERROR_LINE() : Hatanın oluştuğu satırı bildirir.
ERROR_PROCEDURE() : Hatanın oluştuğu stored procedure’un veya trigger’ın adını döndürür

24 Eylül 2008 Çarşamba

SQL 2005 ile database olaylarını izlemek. Loglama

Original:http://www.simple-talk.com/content/print.aspx?article=396





SQL Server 2005 DDL Trigger Workbench

25 May 2007

by Robyn Page and Phil Factor


/* How about automatically tracking and logging all database changes, 
including changes to tables, views, routines, queues and so on? With SQL
Server 2005 it isn't that hard, and we'll show how it is done. If you 
haven't got SQL Server 2005, then get SQL Server Express for free. It 
works on that! While we're about it, we'll show you how to track all
additions, changes and deletions of Logins and Database Users, using
a similar technique.

Contents
   Logging all changes to the database with source code.
   Preventing changes to database objects,
   Logging all changes to the Logins and database users,
   Further reading 
 

Logging all changes to the database with source code.
-----------------------------------------------------

To start off, we'll write a simple trigger that tracks all database 
events. This will include creating, altering or dropping an 
APPLICATION_ROLE, ASSEMBLY, AUTHORIZATION_DATABASE, CERTIFICATE, 
CONTRACT, FUNCTION, INDEX, MESSAGE_TYPE, PARTITION_FUNCTION, 
PARTITION_SCHEME, PROCEDURE, QUEUE, REMOTE_SERVICE_BINDING,
ROLE, ROUTE, SCHEMA, SERVICE, STATISTICS, TABLE, TRIGGER, USER, 
VIEW,  or XML_SCHEMA_COLLECTION. It will also record the creation, 
or dropping of an EVENT_NOTIFICATION, SYNONYM, or TYPE and track 
all GRANT_DATABASE, DENY_DATABASE, and REVOKE_DATABASE DDL.

The new DDL triggers work very like the DML triggers you know and love.
The most radical change is that the details of the event that fired the 
trigger are available only in XML format. You have to get serious with 
XPath queries to extract the XML which is in the format...

<EVENT_INSTANCE>
    <EventType>type</EventType>
    <PostTime>date-time</PostTime>
    <SPID>spid</SPID>
    <ServerName>name</ServerName>
    <LoginName>name</LoginName>
    <UserName>name</UserName>
    <DatabaseName>name</DatabaseName>
    <SchemaName>name</SchemaName>
    <ObjectName>name</ObjectName>
    <ObjectType>type</ObjectType>
    <TSQLCommand>command</TSQLCommand>
</EVENT_INSTANCE>
*/

--Before you do anything else, create a database called TestLogging

USE [TestLogging]
GO
/*now we will create a table that will be a change log. We will put 
in it the detail of each DDL SQL Statement and the user that did it.
We'll trap the login and the original login just to check for context 
switching. We'll record the type of object, the type of event and the 
object name, and, of course the SQL that did it! Who needs source
control?*/
CREATE TABLE [dbo].[DDLChangeLog]
    
(
      
[DDLChangeLog_ID] [int] IDENTITY(11)
                              NOT NULL,
      
[InsertionDate] [datetime] NOT NULL
        
CONSTRAINT [DF_ddl_log_InsertionDate] 
            
DEFAULT GETDATE() ),
      
[CurrentUser] [nvarchar](50) NOT NULL
        
CONSTRAINT [DF_ddl_log_CurrentUser]  
            
DEFAULT CONVERT([nvarchar](50), USER_NAME(), ( )) ),
      
[LoginName] [nvarchar](50) NOT NULL
        
CONSTRAINT [DF_DDLChangeLog_LoginName]  
            
DEFAULT CONVERT([nvarchar](50), SUSER_SNAME(), ( )) ),
      
[Username] [nvarchar](50) NOT NULL
        
CONSTRAINT [DF_DDLChangeLog_Username]  
            
DEFAULT CONVERT([nvarchar](50), original_login(),(0)) ),
      
[EventType] [nvarchar](100) NULL,
      
[objectName] [nvarchar](100) NULL,
      
[objectType] [nvarchar](100) NULL,
      
[tsql] [nvarchar](MAX) NULL
    )
ON  [PRIMARY]

GO
/* now we'll create the trigger that fires whenever any database level
DDL events occur. We won't bother to record CREATE STATISTIC events*/
CREATE TRIGGER trgLogDDLEvent ON DATABASE
    FOR 
DDL_DATABASE_LEVEL_EVENTS
AS
    DECLARE 
@data XML
    
SET @data EVENTDATA()
    
IF @data.value('(/EVENT_INSTANCE/EventType)[1]''nvarchar(100)')
        <> 
'CREATE_STATISTICS' 
        
INSERT  INTO DDLChangeLog
                
(
                  
EventType,
                  
ObjectName,
                  
ObjectType,
                  
tsql
                
)
        
VALUES  (
                   
@data.value('(/EVENT_INSTANCE/EventType)[1]',
                              
'nvarchar(100)'),
                  
@data.value('(/EVENT_INSTANCE/ObjectName)[1]',
                              
'nvarchar(100)'),
                  
@data.value('(/EVENT_INSTANCE/ObjectType)[1]',
                              
'nvarchar(100)'),
                  
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]',
                              
'nvarchar(max)')
                ) ;
GO

--let's create a Table, view, and procedure, and then drop them, and after
-- that, see what was recorded in the log
USE [TestLogging]
GO
CREATE TABLE [dbo].[PublicHouses]--the test Table
    
(
      
[pubname] [varchar](100) NOT NULL,
      
[Address] [varchar](100) NOT NULL,
      
[postcode] [varchar](20) NOT NULL,
      
[outcode] VARCHAR(4)
    )
ON  [PRIMARY]
GO
USE [TestLogging]
GO
CREATE VIEW [dbo].[vCambridgePubs]--the test view
AS  SELECT TOP 100 PERCENT
            
pubname,
            
Address '  ' postcode AS Expr1
    
FROM    dbo.PublicHouses
    
WHERE   postcode LIKE 'CM%' )
GO
CREATE PROCEDURE spInsertPub--the test stored procedure
    
@pubname VARCHAR(100),
    
@Address VARCHAR(100),
    
@postcode VARCHAR(20)
AS 
    INSERT  INTO 
PublicHouse
            
(
              
pubname,
              
Address,
              
Postcode,
              
outcode
            
)
            
SELECT  @pubname,
                    
@Address,
                    
@Postcode,
                    
LEFT(LEFT(@Postcode
                       
CHARINDEX(' '
                       
@Postcode ' ') - 1),
                        
4)
GO
DROP VIEW vCambridgePubs
GO
DROP PROCEDURE spInsertPub ;
GO
DROP TABLE PublicHouses ;
GO
-- now, having done all that we can then see what happened. As you know,
-- this is the only way you'll ever see the current build statements for
-- your tables! Now try changing the database objects via SSMS and have a
-- look at the SQL DDL that gets executed!

SELECT  *
FROM    DDLChangeLog
ORDER BY insertionDate 

-- To help, here is a better rendering of the log. We create an HTML table
--and format it up prettily
DECLARE @HTMLCode VARCHAR(MAX)
SELECT  @HTMLCode COALESCE(@HTMLCode' <style type="text/css">
    <!--
    #changes{
     border: 1px solid silver;
     font-family: Arial, Helvetica, sans-serif;
     font-size: 11px;
     padding: 10px 10px 10px 10px;
    }
    #changes td.date{ font-style: italic; }
    #changes td.tsql{ border-bottom: 1px solid silver; color: #00008B; }
    -->
    </style><table id="changes">
'
) + '<tr class="recordtop">
<td class="date">' 
CONVERT(CHAR(18), InsertionDate113) + '</td>
<td class="currentuser">' 
currentUser '</td>
<td class="loginname">' 
LoginName
        
CASE WHEN loginName <> UserName THEN '(' UserName ')'
               
ELSE ''
          
END '</td>
<td class="eventtype">' 
EventType '</td>
<td class="objectname">' 
ObjectName ' (' objectType ')'
        
'</td></tr>
<tr class="recordbase"><td colspan="6" class="tsql"><pre>' 
tsql
        
'</pre></td></tr>
'
FROM    DDLChangeLog
ORDER BY insertionDate ;
SELECT  @HTMLCode '
</table>'
GO
--Which gives this...




















































25 May 2007
10:47:
dboSIMPLETALK\RobynPageCREATE_TABLEPublicHouses 
(TABLE)
CREATE TABLE [dbo].[PublicHouses]--the test Table

(
[pubname] [varchar]
(100) NOT NULL,
[Address] [varchar]
(100) NOT NULL,
[postcode] [varchar]
(20) NOT NULL,
[outcode] VARCHAR
(4)
)
ON [PRIMARY]
25 May 2007
10:47:
dboSIMPLETALK\RobynPageCREATE_VIEWvCambridgePubs 
(VIEW)
CREATE VIEW [dbo].[vCambridgePubs]--the test view
AS
SELECT TOP
(100) PERCENT pubname, Address + ' ' + postcode AS Expr1
FROM dbo.PublicHouses
WHERE
(postcode LIKE 'CM%')
25 May 2007
10:47:
dboSIMPLETALK\RobynPageCREATE_PROCEDUREspInsertPub 
(PROCEDURE)
Create procedure spInsertPub--the test stored procedure
@pubname varchar
(100),
@Address varchar
(100),
@postcode varchar
(20)
as
insert into PublicHouse
(pubname, Address, Postcode, outcode)
Select @pubname, @Address, @Postcode,
left
(left
(@Postcode, charindex
(' ',@Postcode+' ')-1),4)
25 May 2007
10:47:
dboSIMPLETALK\RobynPageDROP_VIEWvCambridgePubs 
(VIEW)
Drop View vCambridgePubs
25 May 2007
10:47:
dboSIMPLETALK\RobynPageDROP_PROCEDUREspInsertPub 
(PROCEDURE)
DROP PROCEDURE spInsertPub;
25 May 2007
10:47:
dboSIMPLETALK\RobynPageDROP_TABLEPublicHouses 
(TABLE)
DROP TABLE PublicHouses ;

--once we finish logging we can...
--Drop the trigger.
DROP TRIGGER trgLogDDLEvent ON DATABASE
GO
--Drop table ddl_log.
DROP TABLE DDLChangeLog
GO
/*
Of course, this can be very valuable for Database Development work.

Preventing changes to database objects,

---------------------------------------

BOL seem to be very proud of their example code that prevents a table
being altered, though, if you have security nailed down properly, this
shouldn't happen anyway. */

CREATE TRIGGER trgNoMonkeying ON DATABASE
    FOR 
DROP_TABLEALTER_TABLE
AS
    DECLARE 
@Message VARCHAR(255)
    
SELECT  @message 'You are forbiddent to alter or delete the '''
            
EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]',
                                
'nvarchar(100)') + ''' table'
    
RAISERROR @Message16)
    
ROLLBACK ;
GO



CREATE TABLE NewTable Column1 INT ) ;
GO
DROP TABLE NewTable
/*
'Msg 3609, Level 16, State 2, Line 1
The transaction ended in the trigger. The batch has been aborted.
Msg 50000, Level 18, State 1, Procedure trg, Line 8
You are forbiddent to alter or delete the 'NewTable' table'

Logging all changes to the Logins and database users

---------------------------------------------------- 

Another good use for triggers is to provide information about security
 events*/
GO
USE master
GO
--in MASTER, we'll creat a log for all the databases security events. 
CREATE TABLE [DDLSecurityLog]
    
(
      
[DDLSecurityLog_ID] [int] IDENTITY(11)
                                NOT NULL,
      
[InsertionDate] [datetime] NOT NULL
           
CONSTRAINT [DF_ddl_log_InsertionDate] 
               
DEFAULT GETDATE() ),
      
[CurrentUser] [nvarchar](50) NOT NULL
           
CONSTRAINT [DF_ddl_log_CurrentUser] 
               
DEFAULT CONVERT([nvarchar](50), USER_NAME(), ( )) ),
      
[LoginName] [nvarchar](50) NOT NULL
           
CONSTRAINT [DF_DDLSecurityLog_LoginName] 
               
DEFAULT CONVERT([nvarchar](50), SUSER_SNAME(), ( )) ),
      
[Username] [nvarchar](50) NOT NULL
           
CONSTRAINT [DF_DDLSecurityLog_Username] 
               
DEFAULT CONVERT([nvarchar](50), original_login(), ( )) ),
      
[EventType] [nvarchar](100) NULL,
      
[objectName] [nvarchar](100) NULL,
      
[objectType] [nvarchar](100) NULL,
     
[DatabaseName] [nvarchar](100) NULL,
      
[tsql] [nvarchar](MAX) NULL
    )
ON  [PRIMARY]
/*
Now we will write a trigger that inserts into our security log all
server security events. There is a bug which prevents you just 
specifying all the security events, you have to list 'em*/


IF EXISTS ( SELECT  *
            
FROM    sys.server_triggers
            
WHERE   name 'trgLogServerSecurityEvents' 
    
DROP TRIGGER trgLogServerSecurityEvents ON ALL SERVER
GO
CREATE TRIGGER trgLogServerSecurityEvents ON ALL SERVER
    
FOR CREATE_LOGINALTER_LOGINDROP_LOGINGRANT_SERVERDENY_SERVER,
        
REVOKE_SERVERALTER_AUTHORIZATION_SERVER
AS
    DECLARE 
@data XML
    
SET @data EVENTDATA()
    
INSERT  INTO master..DDLSecurityLog
       
(
       
EventType,
       
ObjectName,
       
ObjectType,
       
TSQL,
      
DatabaseName
       
)
    
VALUES
       
(
        
@data.value('(/EVENT_INSTANCE/EventType)[1]''nvarchar(100)'),
        
@data.value('(/EVENT_INSTANCE/ObjectName)[1]''nvarchar(100)'),
        
@data.value('(/EVENT_INSTANCE/ObjectType)[1]''nvarchar(100)'),
          
'Server',
        
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]''nvarchar(max)')
        ) 
GO
/*
Now we have to create another trigger in each database which recors all
the database security changes*/
USE testlogging--back to our database!
GO
CREATE TRIGGER trgLogDatabaseSecurityEvents ON DATABASE
    FOR 
DDL_DATABASE_SECURITY_EVENTS
AS
    DECLARE 
@data XML
    
SET @data EVENTDATA()
    
INSERT  INTO master..DDLSecurityLog
         
(
         
EventType,
         
ObjectName,
         
ObjectType,
        
DatabaseName,
         
tsql
         
)
    
VALUES  
         
(
         
@data.value('(/EVENT_INSTANCE/EventType)[1]''nvarchar(100)'),
         
@data.value('(/EVENT_INSTANCE/ObjectName)[1]''nvarchar(100)'),
         
@data.value('(/EVENT_INSTANCE/ObjectType)[1]''nvarchar(100)'),
         
@data.value('(/EVENT_INSTANCE/DatabaseName)[1]''nvarchar(max)'),
         
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]''nvarchar(max)')
         ) 
GO
/* now everything is in place let's test it. We will simulate an intruder's
cunning attempt to create himself as a loging with sysAdmin rights and his
gaining access as a database user. We could always prevent the transaction 
but that would just draw his attention to the trigger being there!
*/ 

USE [master]
GO
/* Heh! Heh!*/
CREATE LOGIN [Intruder] WITH PASSWORDN'silly'DEFAULT_DATABASE=
    
[TestLogging]DEFAULT_LANGUAGE[Portugu?(Brasil)]CHECK_EXPIRATION=
    OFF
CHECK_POLICY= OFF
GO
EXEC master..sp_addsrvrolemember @loginame N'Intruder',
    
@rolename N'sysadmin'
GO
USE [TestLogging]
GO
CREATE USER [Intruder] FOR LOGIN [Intruder]
GO
--now we will drop the database user
IF EXISTS ( SELECT  *
            
FROM    sys.server_principals
            
WHERE   name N'Intruder' 
    
DROP LOGIN [Intruder]
GO
--and drop the login
DROP USER [Intruder]
GO
/* now we can see that the whole activity has been logged. Because the
initial CREATE  LOGIN contained a password, it has not been recorded.
*/
SELECT  FROM    master..DDLSecurityLog

--so to end up, we just clean up!
DROP TRIGGER trgLogDatabaseSecurityEvents ON DATABASE
DROP TRIGGER 
[trgNoMonkeying] ON DATABASE
GO
USE master
GO
DROP TRIGGER trgLogServerSecurityEvents ON ALL SERVER
DROP TABLE DDLSecurityLog 
GO
USE [TestLogging]
GO
DROP TABLE NewTable
GO

/*
for further reading


   Designing DDL Triggers
   Using the EVENTDATA Function
   Understanding DDL Triggers
   Implementing DDL Triggers


*/
formatted by the Simple-Talk Prettifier




© Simple-Talk.com

XML Dosyalarının İlişkisel Veritabanlarında Saklanması

orjinal: www.teknoturk.org

İnternetin tüm dünyada
yaygınlaşmasıyla birlikte kişiler ve şirketler arası ilişkiler de
başka ortamlardan internete kaymaya başladı. Artık şirketler hem müşterileriyle
hem de kendi ihtiyaçlarını giderecekleri başka şirketlerle iletişim
kurmakta interneti kullanıyorlar. İş hacimleri o kadar büyüdü ki
yapılan işlerin tamamiyle otomatik hale getirilmesi, insan faktörünün
bilgisayarlar arasından çıkarılması bir ihtiyaç haline geldi.
Bunun sonucunda da aradaki iletişimi sağlayacak, platform ve işletim
sistemlerinden bağımsız, standart veri değişim ortamlarına ihtiyaç
duyuldu. İşte XML, dev boyutlardaki bu insanlı ve insansız pazarlıklar,
anlaşmalar ve siparişlerin sağlanabilmesi için bir iletişim dili
olarak geliştirildi. 


XML’in bu kadar yaygın
kullanımıyla birlikte standart veritabanı formatından farklı,
hiyerarşik yapıya sahip bu dosyaların saklanması ve sorgulanması
sorunu ortaya çıktı. XML dökümanları üzerinde sorgulama yapmaya
imkan veren bazı diller geliştirildiyse de bunlar hem gelişmiş bir
index mekanizması olmadığından, hem de yeterince olgunlaşmadıklarından
ihtiyaca cevap veremiyorlar. Üstelik de mevcut tüm veriler ilişkisel
veritabanlarında saklanırken, aynı verilerle birlikte kullanılacak
XML belgelerinin farklı bir sistemde saklanması fazladan bir yük
getiriyor. Bu yüzden de, mevcut sistemlerin tüm avantajlarını
kullanabilmek ve XML belgelerini ilişkisel veritabanlarında
saklayabilmek amacıyla farklı yöntemler geliştirilmekte.


Bilindiği gibi XML dökümanlarının
belirli bir formata uygun olduğunun denetlenmesi DTD’ler (Document
Type Definition) sayesinde olabiliyor. DTD hangi isimli elemanın doküman
içerisinde yer alabileceğini, hiyerarşik yapının ne olacağını,
olması mecburi olan ve olmayan elemanların hangileri olduğunu gösteriyor.
Başka bir deyişle herhangi bir dökümanın önceden belirlenmiş bir
yapıda olmasını sağlayabiliyoruz DTD’ler sayesinde.


Hal böyle iken
XML’lerin ilişkisel veritabanlarında saklanması için en çok başvurulan
yöntem bu format bilgisini kullanmak. Şirketler kendi aralarındaki
yazışmalarını her zaman belirli bir formata uygun yaptıkları için
gelen dökümaların standartlar dışında olması çok sık rastlanan
bir durum değil. O yüzden de standart bir veritabanı şeması çıkarıp
gelen dökümanları buna uygun olarak saklamak pek çok durumda makul
bir çözüm sunuyor.


Bu yöntemi biraz daha
ayrıntılı ele alırsak şu şekilde özetlemek mümkün:
 




  • DTD’ye uygun bir veritabanı şeması çıkarılır.

  • Bu yapıya uygun bir veritabanı yapısı oluşturulur.

  • Gelen XML dökümanları veritabanı sisteminin indeksleme yötemlerini
    kullanarak bu yapı içerisinde saklanır.

  • Sorgulama gerektiğinde XML sorgulama dillerinden birisi standart
    veritabanı sorgulama dili olan SQL’e çevrilerek sistemin sorguyu gerçekleştirmesi
    sağlanır.


  • Dönen sonuçlar uygun şekilde formatlanarak kullanıcıya gönderilir.




Bu yöntemi kullananlar
tablolarda saklanacak bilgiyi belirlerken farklı yaklaşımlar
sergiliyorlar. Her bir elemanı ya da önceden çıkarılmış bir XML
yapı ağacına göre belirlenen eleman gruplarını ayrı ayrı
tablolarda saklamak yaklaşımlardan iki tanesi. Ancak burada karşılaşılan
bazı sorunlar var. Öncelikle XML DTD’lerinde * ya da + işaretleriyle
belirtilen seçmeli elemanların geleneksel veritabanlarında temsil
edilmesi problem oluşturuyor. Çünkü geleneksel veritabanlarında bir
kayıt ya vardır ya yoktur. Veritabanı yapısı aynı tür kayıtların
bazen olup bazen olmayacağı varsayımına göre şekillendirilemez.
Buna önerilen çözüm * işaretiyle gösterilen elemanların yapı içerisinde
NULL (yok) değerlerini de içerecek şekilde saklanması ama + ile gösterilen
elemanların NULL değerini alamaması.


İkinci problem,
DTD’lere birgün lazım olabilir düşüncesiyle yerleştirilmiş, ama
günlük yazışmalarda hiç kullanılmayan bazı elemanların veritabanı
yapısında varolmasından kaynaklanan sistem yükü. Başka bir deyişle
hiç varolmayan ve kullanılmayan elemanlar yüzünden sistemin yapmak
zorunda kalacağı tablolar arası birleştirme işlemi (join
operation). Bunun çözümü olarak önerilebilecek yöntemlerden birisi
veritabanında yalnızca elemanları değil farklı veri türlerini,
daha açıkçası XML türünde bir veri yapısını tutmak. Az kullanılan
ya da kullanılmayan veri parçaları, olduğu gibi, XML halinde saklanırsa
sistemin bahsedilen türdeki yavaşlamaları azalacaktır. Önerilebilecek
bir diğer yöntem, hiç kullanılmadığı istatistiksel olarak tespit
edilen veri parçalarının, veritabanı şeması oluşturulurken
dikkate alınmaması olabilir.


Bir diğer problem yine
sistem yük getiren ama hiçbir zaman sorgulanmayan elemanlar olabilir.
Yukarıdaki sebepten bu tür veriler de sisteme gereksiz yük
getirmektedir. Bu tür veriler de istatistiksel yöntemler yardımıyla
belirlenip XML türünde saklanırsa, bunlardan kaynaklanan gereksiz
birleştirme işlemlerinden kurtulabiliriz.


Bu yöntemin kullanılmasında
karşılaşılan sorunlardan bir diğeri dönüşlü (recursive) yapıların
ve IDREF türündeki eklerin (attribute) veritabanında tanımlanması.
Geleneksel veritabanlarında dönüşlü yapılar olmadığından
DTD’lere bağlı bir şema oluşturulurken bu yapıların aktarılması
bugüne kadar ciddi bir çözüme kavuşturulabilmiş değil. Aynı şekilde
geleneksel veri türleri kullanılarak da aslında liste olan IDREF türündeki
verilerin saklanması mümkün değil ve bu da genel kabul gören bir
çözüme henüz kavuşturulabilmiş değil.


DTD kullanarak, oradaki
bilgi yardımıyla oluşturulacak bir veritabanı yapısının en önemli
sorunu, zaman içerisinde standart DTD yapısında meydana gelecek bir
değişmenin veritabanı yapısını doğrudan etkilemesi. Sonradan oluşacak
bu tür değişiklikleri veritabanı yapısına yansıtırsak, önceki
verilerimiz arasında uyumsuzluklar meydana gelecektir. Daha önceden geçerli
olan bazı verilerimiz artık geçersiz hale gelebilecek, veriler arasındaki
uyum zorunluluklarında (data integrity rules) değişiklik meydana
gelebilecektir. Bu probleme önerilebilecek çözüm, veritabanının
tarihe göre yapılandırılması olabilir. Yani farklı tarihlerde yapılan
değişilikler göz önüne alınarak, değişilikten önce ve sonra
farklı verilerin ve kuralların geçerli olduğu bilgisi ihmal
edilmeden ekleme, çıkarma ve sorgulama yapılmalıdır.


Daha makul bir yaklaşım
ise veritabanı şeması oluşturulurken DTD’nin hiç dikkate alınmaması.
Bu yöntemde tüm elemanlar, ekler (attribute) ve içerik olan yazılar
ayrı ayrı tablolarda saklanıyor. Her bir elemanın hiyerarşik yapı
içerisindeki yeri bir tabloda saklanırken elemanlar ve içerikleri
farklı bir tabloda tutuluyor. Böylece DTD’ye bağlı kalmaksızın
herhangi bir XML belgesinin saklanması sağlanabiliyor.


Bu yöntemin sıkıntılı
yanlarından birisi sorgulama sonucunda elde edilen bilgilerin kullanıcıya
uygun formatta ve hiyerarşik yapıyı yansıtacak şekilde verilmesi sırasında
fazlaca işlem gerektiriyor olması. Sistemin yapısı gereği yalnızca
bir elemanın döndürülebildiği bu yöntemde, sonraki işlemler sırasında
defalarca veritabanına erişim bile gerekli olabilmektedir.


Anılması gereken diğer
bir sorun da tüm verilerin yalnızca üç dört tabloda tutulması
sonucu zaman içerisinde veritabanı yapısının büyüyerek birleştirme
(join) sırasında farklı dökümanlardaki bilgilerin de gereksiz olduğu
halde kullanılıyor olması. Gereksiz yere gerçekleşen bu işlemler
sonucunda sistem ilgisiz pek çok birleştirme ve kontrol de yapmak
zorunda kaldığından performansı bundan olumsuz etkilenecektir.


Veritabanında saklanan
XML belgelerinin sorgulanmasında uygulanan temel yöntem, kullanılan yönteme
uygun bir XML sorgulama dilinin kullanıcının görmediği alt
seviyelerde standart veritabanı sorgulama dili olan SQL’e çevrilerek
veritabanı sisteminin bu sorguyu çalıştırmasının sağlanmasıdır.
Her sistem için uygun olan XML sorgulama dili farklı olabilir. Örneğin
DTD’ye bağlı olarak ve XML veri türü kullanılmadan gerçekleştirilen
sistemlerde XML-QL uygun bir dil olarak ortaya çıkarken DTD’den bağımsız
sistemlerde her bir elemana ulaşan yol tek bir tabloda tüm hiyerarşiyi
temsil edecek şekilde saklandığı için XQL daha uygun bir dil olarak
kendini belli etmektedir.


Buraya kadar yazdıklarımızı
özetleyecek olursak şunları söyleyebiliriz:



  • XML kişiler ve özellikle de şirketler arasında bilgi değişimi
    için ortak dil olma yolundadır ve büyük ihtimalle kısa süre
    sonunda internetin standart dili olacaktır.

  • Şirketler arası bilgi değişiminde XML formatında giden ve
    gelen verileri diğer verilerle birlikte aynı ilişkisel veritabanı
    sisteminde tutmak hem daha kolay, hem de daha ucuz olduğundan tercih
    edilmektedir.

  • XML belgelerinin ilişkisel veritabanına aktarılmasında kullanılan
    yöntemleri XML formatını belirleyen DTD’lere bağlı olarak ikiye
    ayırmak mümkündür.

  • DTD’ye bağlı sistemler kendi içinde küçük farklılıklar
    gösterse de temel olarak XML dökümanlarının DTD’ye uygun olarak
    şekillendirilmiş bir veritabanı yapısında saklanması ve
    sorgulanması esasına dayanır.

  • DTD’den bağımsız sistemler saklanacak tüm belgelerdeki tüm
    bilgileri aynı tablo yapısı içerisinde saklamayı öngörmektedir.

  • DTD’ye bağlı sistemlerin en önemli problemi veritabanı yapısının
    durağan olması ve DTD’de meydana gelecek bir değişikliğin
    veritabanına yansıtılmasının oldukça sıkıntılı olmasıdır.

  • Buna karşın DTD’den bağımsız sistemlerde tablolar zaman içerisinde
    fazla büyüyerek birleşme (join) işlemler sırasında gereksiz birleştirme
    ve hesaplamaların yapılmasını gerekli kılmaktadır ve sistem
    performansı olumsuz etkilenmektedir.

  • İlişkisel veritabanlarında saklanan XML belgelerinin
    sorgulanmasında kullanılan temel yöntem sistemin SQL ile sorgulanması
    ve sonuçların uygun formatta kullanıcıya döndürülmesi esasına
    dayanmaktadır.



Şu anda endüstride önde
gelen şirketlerin çoğu bu konuda araştırmalar yapmakta ve yeni çıkan
veritabanı ürünlerinde XML belgelerinin saklanmasına da yer
vermekteler. Oracle, Sybase, Microsotf (SQL Server 2000), IBM ve daha
pekçok şirket ürünlerinin XML destekli olduğu iddiasıyla piyasaya
girdiler bile. Henüz yeterli olgunlukta olmasa da temel seviyedeki işlemlerin
yapılması ve XML dökümanlarının veritabanına iyi ya da kötü
aktarılması için bu ürünler kullanılmaya başlandılar.


Sonuç
olarak diyebiliriz ki XML belgelerinin ilişkisel veritabanlarında
saklanması henüz üzerinde yeterince araştırma yapılmış ve
belirli bir olgunluğa ulaştırılmış bir konu değildir. Belgelerin
saklanması için çok sayıda yöntem önerilmekle birlikte herkesin üzerinde
ittifak edebileceği verimlilikte bir sistem henüz geliştirilebilmiş
değildir. Gelecekte ciddi bir pazar olacağı düşüncesiyle önde
gelen şirketlerin hemen hepsi bu konuda ürünler geliştirmeye başladılar
ve hala araştırılmaya muhtaç bir alan olarak bu konu araştırmacıları
ve girişimcileri beklemekte.

XML i Schema ile eşleştirmek.


    1 <?xml version="1.0" encoding="utf-8"?>
    2 <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    3   <xs:element name="KanTahlilleri">
    4     <xs:complexType>
    5       <xs:sequence>
    6         <xs:element maxOccurs="unbounded" name="tahlil">
    7           <xs:complexType>
    8             <xs:sequence>
    9               <xs:element name="adi" type="xs:string" />
   10               <xs:element name="kisaltma" type="xs:string" />
   11               <xs:element name="butceKodu" type="xs:string" />
   12               <xs:element name="islemDurum" type="xs:unsignedByte" />
   13               <xs:element name="adet" type="xs:unsignedByte" />
   14               <xs:element name="alisTestCode" type="xs:string" />
   15             </xs:sequence>
   16           </xs:complexType>
   17         </xs:element>
   18       </xs:sequence>
   19     </xs:complexType>
   20   </xs:element>
   21 </xs:schema>





    1 <?xml version="1.0" encoding="utf-8" ?>
    2 <KanTahlilleri  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="\\192.168.1.80\c$\Inetpub\wwwroot\export\KanTahlilleri.xsd">
    3 
    4   <tahlil>
    5     <!-- Giriş Üre. -->
    6     <adi>Giriş Üre</adi>
    7     <kisaltma>K</kisaltma>
    8     <butceKodu></butceKodu>
    9     <islemDurum>1</islemDurum>
   10     <adet>2</adet>
   11     <alisTestCode>01</alisTestCode>
   12   </tahlil>
   13   <tahlil>
   14     <!-- Giriş Kreatinin. -->
   15     <adi>Giriş Kreatinin (  mg/dl)</adi>
   16     <kisaltma></kisaltma>
   17     <butceKodu></butceKodu>
   18     <islemDurum>1</islemDurum>
   19     <adet>1</adet>
   20     <alisTestCode>02</alisTestCode>
   21   </tahlil>
   22   <tahlil>
   23     <!-- Sodyum. -->
   24     <adi>Sodyum</adi>
   25     <kisaltma>Na</kisaltma>
   26     <butceKodu></butceKodu>
   27     <islemDurum>1</islemDurum>
   28     <adet>1</adet>
   29     <alisTestCode>03</alisTestCode>
   30   </tahlil>
   31 
   32 </KanTahlilleri>