1

Konu: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

örneğin 3 fieldli 4 kayıtlı bir cursor var: cursor4sira
şimdiki bilgime göre yaptığım

Visual Fox Pro
m.lnh=SQLSTRINGCONNECT("xxx")

SCAN  && 4 kere SQLSERVER'e bilgi gidiyor
  SCATTER MEMVAR
  SQLECEC(m.lnH,"INSERT INTO [xx]..[sqldosya] (sqlbir,sqliki,sqlüç) VALUES (?m.bir,?m.iki,?m.üç)")
ENDS
SQLDISCONNECT(0)

SORU: yapmak istediğim; örneğin

Visual Fox Pro
SELE * FROM cursor4sira INTO ARRAY arraySQLeYollanacak

SQLEXEC(m.lnh, "ARRAYYOLLA(arraySQLeYollanacak)")


veya

Visual Fox Pro
SQLEXEC(m.lnh, "CURSORYOLLA(cursor4sira)")

tek komutla SQL'e kaydedeceğim bütün datayı yollayıp , gerisini STORED PROCEDURE ile halletmek . (yanıt XML mi acaba- nasıl)

VFP9 SP2

2

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

blockwrite olayı var sql server'da. text veya xml (sanırım başka dosya türlerini de destekliyor). ama hiç kullanmadım.

Haksızlıklar karşısında susanlar, dilsiz şeytanlardır!
www.metinemre.com

3

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Merhabalar:) Birden fazla yolu var. Hangi yolun secilecegi bir kac faktore bagli:

a) SQL server versiyonu 2008' mi yoksa daha oncesi mi? SQL 2008'de tek bir insert ile bircok kayit insert edilebiliyor:

Visual Fox Pro
local array laData[1]

select f1,f2,f3 from myTable into array laData
if _Tally > 0
   local row,lcSQL
   set textmerge to memvar lcSQL noshow
   set textmerge on
   \\ insert into [xx]..[sqldosya] (sqlbir,sqliki,sqlüç) values
   for row = 1 to alen(laData,1)
         \ ( ?laData[<< m.row >>, 1], ?laData[<< m.row >>, 2], ?laData[<< m.row >>, 3]  )
         if m.row < alen(laData, 1)
             \\,
         endif
   endfor
   set textmerge to
   set textmerge off
   m.lnh=SQLSTRINGCONNECT("Driver={SQL Server Native Client 10.0};server=.\sql2008;Trusted_Connection=yes;Database=test")
   SQLExec(m.lnh, m.lcSQL) 
   SQLDISCONNECT(0)
endif

(eger .Net kullaniyor olsaydik bunun yerine dogrudan bir 'table'i parametre olarak gonderebiliyorduk:( VFP ile yapilabilir mi cok derinlemesine bakmadim).

Bu, kayit sayisi cok fazla degilse, tek seferde insert etmek icin kullanilabilecek bir yontem (SQL 2008).

2) SQL versiyonu ne olursa olsun kayit sayisi az mi cok mu. Az ise:

Visual Fox Pro
Local Array laData[1]

Select f1,f2,f3 From (_samples+'data\customer') Into Array laData
If _Tally > 0
  Local Row,lcSQL
  Set Textmerge To Memvar lcSQL Noshow
  Set Textmerge On
  For Row = 1 To Alen(laData,1)
       \ insert into [xx]..[sqldosya] (sqlbir,sqliki,sqlüç) values
       \\ ( ?laData[<< m.row >>, 1], ?laData[<< m.row >>, 2], ?laData[<< m.row >>, 3]  );
  Endfor
  Set Textmerge To
  Set Textmerge Off
  m.lnh=Sqlstringconnect("Driver={SQL Native Client};server=.\sql2008;Trusted_Connection=yes;Database=test")
  SQLExec(m.lnh, m.lcSQL)
  SQLDisconnect(0)
Endif

Bir baska yontem (bir kez compile + N kez insert ):

Visual Fox Pro
LOCAL lcSQL

lcSQL = 'INSERT INTO [xx]..[sqldosya] (sqlbir,sqliki,sqlüç) VALUES (?m.bir,?m.iki,?m.üç)'
 
m.lnh=SQLSTRINGCONNECT("Driver={SQL Server Native Client 10.0};server=.\sql2008;Trusted_Connection=yes;Database=test")
SQLPrepare(m.lnh, m.lcSQL) && Compile 
 
SCAN  && 4 kere SQLSERVER'e bilgi gidiyor
  SCATTER MEMVAR
  SQLExec(m.lnH) && compile edilmis kodu kullan
ENDS
SQLDISCONNECT(0)

Bu yontemler az kayitla efektif calisiyor. Diger bir yontem CursorAdapter kullanmak. CursorAdapter'in BatchUpdateCount propertysi var . 100 dersen (benim denemelerimde cok buyuk kurmanin bir faydasi olmuyor, bir yerden sonra ayni, 100 ortalama iyi bir deger gibi) tek seferde o 100 gondererek update ediyor (select ... where 1=2 ile baslarsan hepsi Insert olacak).

Parametre giden yontemlerde 3 field icin pratikte 700 kayit sinirin var (SQL server maximum parametre sayisi 2100 eger yanlis hatirlamiyorsam).

3) Eger kayit sayisi cok ise:
a) http://www.fox4um.com/topic/1214/sqlbulkcopy/

benim bugune kadar bulabildigim en efektif yontem. Gerekirse dll'i filan hazir gonderirim:)

b) VFP datasini text dosyasina copy to ile transfer edip SQL server'dan 'Bulk Copy' ile okumak (SQL server text dosyasina ulasabilmeli)

c) SQL server'da once bir linked server olusturmak (kodla olabilir - SQL server'a erisim haklarina bagli). Sonra da istenilen VFP dosyasindan query yapmak. Soyle birsey:

Visual Fox Pro
TEXT TO lcLinkedYarat noshow

EXEC sp_addlinkedserver
    @server = N'VFP_SERVER',  -- linked server adi
    @srvproduct=N'Visual FoxPro 9',  -- ne istersen olabilir
    @provider=N'VFPOLEDB',
    @datasrc=N'"C:\PROGRAM FILES\MICROSOFT VISUAL FOXPRO 9\Samples\data\testdata.dbc"'
ENDTEXT
 
* Bir kez yapmak gerekiyor
SQLEXEC(m.lnh, m.lcLinkedYarat)

VFP'den kodla yapmak yerine SQL server management kullansak da olurdu. Bir kez yapildi mi artik VF_SERVER diye VFP datasina ulasan bir kaynak var (northwind benzeri dataya insert - VFP"den select, SQL'e insert):

Visual Fox Pro
TEXT TO lcSQL noshow

insert mySQLTable (orderId, orderDate,shippedTo)
Select * From openquery(VFP_SERVER,
'Select
  order_ID,
Cast(Evl(order_date,Null) As DateTime) As order_Date,
TRIM(to_Name)
from customer')
ENDTEXT
 
SQLEXEC(m.lnh, m.lcSQL)

Not: Burada OpenQuery() icindeki SQL VFP'nin anlayacagi SQL, VFP tablosuna yapiliyor. Sadece basta ve sonda tirnak isareti var, gerisi normal ; kullanilmadan yazilabiliyor.

d) XmlBulkCopy, SQL Server'in For XML gibi baska yontemlerde var ama bana hem yavas geldi hem de ben beceremedim cok karmasik, birinde calisiyor digerinde calismiyor, yazmasi da cok zor geldi:

4 Son düzenleyen, ugurlu2001 (11.12.2009 14:21:05)

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Üstad bir soruda ben sorsam?

Peki SQL Servar 'a, bir yerine , birbiriyle ilgili bir kaç ( sayısı değişebilir ) cursor yollasak. Bu cursorleri bir Stored Procedure içinden kullanmak istesek:
(FaturaNo, FaturaDetay, ÜrünDetay) .. gibi

Yani ali Abinin sorusunu şu şekilde sormuş olsam :
Select * From Cursor1 Into Cursor Crs1
Select * From Cursor2 Into Cursor Crs2
Select * From Cursor3 Into Cursor Crs3
Select * From Cursor4 Into Cursor Crs4

SQLEXEC(m.lnh, "CURSORYOLLA(Crs1)","CURSORYOLLA(Crs2)","CURSORYOLLA(Crs3)","CURSORYOLLA(Crs4)")

Birde fikir edinmek için soruyorum :
Bir tek XML dosyası içerisine, cursorleri yerleştirip, parametre olarak XML i kullanmak daha mı mantıklı. (Cursorlerde az sayıda kayıt olduğunu varsayarak),

Uğur
-------------------------------------------------------------------------------------------------------------
Hayat bir bisiklete binmek gibidir. Pedalı çevirmeye devam ettiğiniz sürece düşmezsiniz. Claude Peppeer
Kusuru söylenmeyen adam, ayıbını hüner sanır.  Türk Atasözü

5

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Çetin,
öncelikle çok teşekkürler. 1. metod aradığım galiba.
"kayit sayisi cok fazla degilse" den anladığım örneğin tablo uzunluğu x alan sayısı diyelim ki 500 den az olanlar gibi oldu.
Ayrıca insert değil de sqlserver tarafında bir cursor yaratmaya çalışıyorum.

Derdim database integrityden dolayı datayı bir kere set olarak yolladım mı sqlserver tarafında bütün işlemleri yapayım. - daha önce yazdığım başlıkta SQLde SCANi keşfettim ya ! :]

önerdiğin 2. metodta sqlservere 1 kere gibi gidiyor gözükse galiba döngü kadar gidiyor, ya da ben mi yanılıyorum.

3lerde ise yollanacak data clientta olunca, çok kullanıcılı ortamda servera değişik adlarla kaydedip Sqlservere okutma karmaşası çıkıyor galiba.
yani sqlservere dosya adını parametre olarak göndermek gerekiyor galiba.

VFP9 SP2

6

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

2. metodda 2 yontem var. Ilkinde VFP tarafinda bir defada N tane insert komutu yazilip tek seferde godneriliyor. SQL server'a giden kabaca:

insert into xx..yy (f1,f2,f3) values (1,2,3);
insert into xx..yy (f1,f2,f3) values (4,5,6);
insert into xx..yy (f1,f2,f3) values (7,8,9);

gibi. Bu komple tek 'batch' olarak gidiyor (tek SQLExec() ). SQL tarafinda ise 3 insert.

Ikinci metodda ise insert VFP tarafinda bir tane, once compile ediliyor, compile edilmis kod her bir insert icin cagiriliyor (SQL server'a giden komutlar once compile ediliyor - SQL 2000'den yana caching nedeniyle pek de esprisi kalmadi bu yontemin).

Bu yontemler parametre ile calistigindan bir kerede gonderilebilecek kayit sayisi:
kayitSayisi * alanSayisi = max 2100 sekilde
500 field varsa bir seferde 4 insert.

3'te gecici dosyalar kullanilabilir, isimler cakismaz ya da 3-a'da data client'in kendi dizinlerinden alindigi icin cakisma da yok. 3 serisinin avantaji en hizli yontemler olmalari.

7

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

ugurlu2001 yazdı:

Üstad bir soruda ben sorsam?

Peki SQL Servar 'a, bir yerine , birbiriyle ilgili bir kaç ( sayısı değişebilir ) cursor yollasak. Bu cursorleri bir Stored Procedure içinden kullanmak istesek:
(FaturaNo, FaturaDetay, ÜrünDetay) .. gibi

Yani ali Abinin sorusunu şu şekilde sormuş olsam :
Select * From Cursor1 Into Cursor Crs1
Select * From Cursor2 Into Cursor Crs2
Select * From Cursor3 Into Cursor Crs3
Select * From Cursor4 Into Cursor Crs4

SQLEXEC(m.lnh, "CURSORYOLLA(Crs1)","CURSORYOLLA(Crs2)","CURSORYOLLA(Crs3)","CURSORYOLLA(Crs4)")

Birde fikir edinmek için soruyorum :
Bir tek XML dosyası içerisine, cursorleri yerleştirip, parametre olarak XML i kullanmak daha mı mantıklı. (Cursorlerde az sayıda kayıt olduğunu varsayarak),

Ugur,
Bu dun gozumden kacmis.

SQL server'a cursor yollamak demek datayi zaten SQL server'da insert etmek demek. Gecici tablo kullanimi pek tavsiye edilen birsey degil (performans acisindan). Oradan da asil tabloya insert edeceksin, isi daha da yavaslatir. Ancak demek istedigin SQL2008'in yeni tablo parametresini kullanmak ise VFP ile yapilabilir mi, yapilirsa nasil yapilir hic fikrim yok.

XML kullanmayi tavsiye etmem, cunku XML hemen hemen her zaman daha cok verinin gidip-gelmesini gerektiriyor + XML'in cevrim islemleri isi daha da yavaslatiyor. XML kucuk data icin olur. XML kayit basina gereksiz sekilde field adlarini tekrarlayan bir yontem - ilk ciktiginda amaci simdiki gibi data transferi degildi ondan herhalde oyle gereksiz tekrarlari.

8

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Çetin,
Uğur ile aynı soruyu kelimelerin yerini değiştirerek gene soracağım affola:

Ben datayı bir dataset olarak bir SQLserver tarafında bir cursora (veya geçici bir kütüğe)  yüklemek istiyorum. 1. metodla OK, zaten en fazla 10 kayıt x 2 alan (tekstilId,adet) falan gidiyor
Derdim sonraki işlemleri SQLserver tarafında yapıp -3-4 tane tableda insert ve update ve delete yapacağım.
Yani peşpeşe VFP komutu olarak yaptığımda connection yüzünden aksama olursa database integrityyi bozulur diye korkuyorum...
BEGIN END ROLLBACK muhabbetine gene connection olarak girmek istemiyorum. (Hani Türk filimlerinde filmin manasını gözardı edip "sonunda kahraman öldü mü" diye görmek isteriz ya- o sendrom)
O nedenle VFP tarafından gelen bir INSERT değil de SQL tarafında bir cursor arıyorum. Devamını STORED PROCEDUR ile trigger falan halletmeyi düşünüyorum....

VFP9 SP2

9

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

O zaman Ugur'un dedigi gecerli:) # kullanarak gecici bir tablo (VFP terimiyle cursor) yaratabilirsin. SQL server acisindan onun normal tablodan hicbir farki yok, connection aktif oldugu surece kullanabilirsin, kapaninca otomatikman SQL server kaldirir ( ya da sana gerekli ise arada Drop Table ile sen kapatabilirsin - bu tablolar Temp database'de yaratiliyor ama teknik detay). Ornek gonderecegim simdi ama bu bilgisayari kapatmak zorundayim. Baska yerden bir sure sonra gonderiyorum:)

10

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Visual Fox Pro
Close Databases All

Clear
 
lnHandle = Sqlstringconnect('Driver={SQL Server Native Client 10.0};Trusted_Connection=yes;server=.\sqlexpress')
 
** Database yarat
SQLExec(m.lnHandle, 'create database test')
 
** Bu database'i aktif database yap
SQLExec(m.lnHandle, 'use test')
 
** Ornek tablo yarat
SQLExec(m.lnHandle, 'create table Musteri ('+;
    ' musteriID varchar(6) primary key,'+;
    ' sirket varchar(100),'+;
    ' ulke varchar(20))' )
 
** ornegi testdata.dbc'den doldur
Use (_samples+'data\customer')
 
** SQL komutu hazirla ve derle
SQLPrepare(m.lnHandle, 'insert into Musteri'+;
    ' (musteriID, sirket,ulke)'+;
    ' values'+;
    ' (?TRIM(customer.cust_id), ?TRIM(customer.Company), ?ALLTRIM(customer.Country))' )
 
** En sondaki ALLTRIM() kasitli.
** SQL server'da TRIM() var ama ALLTRIM() diye bir function yok.
** Basindaki soru isareti nedeniyle o bir parametre
** ve VFP tarafinda degerlendiriliyor
** ALLTRIM()'i (ve TRIM()leri) yapan VFP
 
** ornek datayi yaz
Scan
    SQLExec(m.lnHandle)
Endscan
 
** Temp tablo ornegi
SQLExec(m.lnHandle, 'create table #ulkeler (Ulke varchar(20))')
 
** #ulkeler tablosu lnHandle Connection aktif oldugu surece
** (yalnizca bu baglanti icin) mevcut
** baska baglantilar da kullansin dersen cift # kullanmak gerekiyor
** ##ulkeler
 
** Temp tabloya data koyalim
ulke = 'USA'
SQLExec(m.lnHandle, 'insert into #ulkeler values (?m.ulke)')
ulke = 'UK'
SQLExec(m.lnHandle, 'insert into #ulkeler values (?m.ulke)')
 
** Data artik SQL server tablosunda olduguna gore
** SQL server'da join'de ya da stored procedure'da
** kullanabiliriz
 
** Join
TEXT TO lcSQL noshow
select musteri.* from Musteri
inner join #ulkeler
       ON [musteri].[ulke] = [#Ulkeler].[ulke]
ENDTEXT
SQLExec(m.lnHandle, m.lcSQL, 'crsJoin')
 
Select crsJoin
Browse
 
** Stored Procedure
TEXT TO m.lcSQL noshow
CREATE procedure UlkeEkle (@ulkeAdi varchar(20))
as
BEGIN
   DECLARE @sayi int
   select @sayi=COUNT(*) from #ulkeler where ulke = @ulkeAdi
   IF ( @sayi = 0 )
       begin
          INSERT INTO #ulkeler VALUES (@ulkeAdi)
       end
end
ENDTEXT
 
SQLExec(m.lnHandle, m.lcSQL)
 
** Stored Procedure
TEXT TO m.lcSQL noshow
CREATE procedure UlkeSorgu
as
BEGIN
  SELECT * FROM musteri WHERE ulke in
  (select ulke from #ulkeler);
end
ENDTEXT
 
SQLExec(m.lnHandle, m.lcSQL)
 
** SP'leri kullan
lcUlke = 'Germany'
SQLExec(m.lnHandle, 'Exec dbo.UlkeEkle ?m.lcUlke')
 
lcUlke = 'Argentina'
SQLExec(m.lnHandle, 'Exec dbo.UlkeEkle ?m.lcUlke')
 
SQLExec(m.lnHandle, 'select * from #ulkeler', 'tempUlkeler')
Select tempUlkeler
Browse
 
 
SQLExec(m.lnHandle, 'Exec dbo.UlkeSorgu', 'SPSorgu')
 
Select SPSorgu
Browse
 
** Tablo hala ulasilabilir
SQLExec(m.lnHandle, 'select * from #ulkeler', 'tempData1')
Select tempData1
Browse
 
SQLDisconnect(m.lnHandle)
 
** Tablo artik ulasilamaz durumda kapandi
 
lnHandle = Sqlstringconnect('Driver={SQL Server Native Client 10.0};Trusted_Connection=yes;server=.\sqlexpress')
 
lnResult = SQLExec(m.lnHandle, 'select * from #ulkeler', 'tempData2')
If m.lnResult < 0
    Aerror( aNeden )
    Display Memory Like aNeden
Else
    Select tempData2
    Browse
Endif
 
SQLDisconnect(m.lnHandle)

11

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

Çetin çözümün için çok teşekkürler.
Bu başlıkla ilgili başka bir çözüm bugün çıktı, paylaşıyorum: (Array->String->table)

Convert String to a Table using CTE
By Amit Gaur, 2009/12/14

Introduction

Many times we have faced this problem: we have an array of IDs in our program that we want to pass as a parameter to a stored procedure. In the stored procedure we would like to use this data, only we wish if it would have been passed as a table.

devamı: http://www.sqlservercentral.com/articles/CTE/67974/

VFP9 SP2

12

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

bu konu ile makale çıktı:
1. delimated text şeklinde, başlıkta tartıştığımız şekilde
http://www.sqlservercentral.com/article … ted/67417/

2. xml şeklinde (bu yeni)
http://www.sqlservercentral.com/articles/T-SQL/67603/

----
bir de karşılaştırma yapmış, aşağıda:

Comparison between parsing of delimited string and xml data

In this two part article, I have tried to present the following two efficient approaches to work around the problem of sending multiple rows to the data base for update:

   1. Delimited String Approach - explained in part I of this article
   2. XML data approach - explained in part II of this article.

I now present a comparison of both these approaches highlighting the pros and cons of each approach.
Delimited string Approach

Pros

    * Easy to parse at the database side.
    * Easy to create at the application layer.

Cons

    * Manual parsing, need to write logic to parse. (In our case we have written table valued functions.)
    * Need to pass as many delimited strings as the number of parameters.
    * Since, delimited string would be passed as a string data type, so limitation of size of string data supported in SQL Server 2005 comes into picture (4000 / 8000 characters max including the delimiter character).
    * Choosing a delimiter character, as it should never occur in your data.

XML Data

Pros

    * Supports large size of data (up to 2 GB).
    * Only one parameter needs to be sent from application layer.
    * No manual parsing, handled by XQuery functions.
    * Passed XML can be validated with an XSD.

Cons

    * Complex to parse (need to have knowledge of XQuery functions).
    * Difficult to create XML data at the application layer.

Conclusion

In this article, we discussed about the XQuery functions and how to convert an XML into a table using them.
In the first article of the series, "Sending Multiple rows to Database for Update - Part I", we already discussed about, how we can send a delimited string to the database for update.

Hope these two articles help you to modify multiple records in database in a single database call.

These articles would also be helpful where an application works in disconnected environment. A user can save data in a disconnected environment using either of these two approaches. When the user will be online or connected to database and wants to update the modified records, all that data can be passed to the database for updating using either a delimited string or an XML.

VFP9 SP2

13

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

SQL tarafına Bulk insert için XML veya SP+XML kullanma
http://www.sqlservercentral.com/articles/Stairway+Series/The+XML+Data+Type/92781/

VFP9 SP2

14

Re: SQL servere birden fazla kayıt tek komutla yollanabilir mi?

"SQL tarafına Bulk insert için XML veya SP+XML kullanma " yi ben once "nasil kullanilir" yerine "kullanma" olarak algiladim:) Eger oyle olsaydi ayni fikirde olurduk, bence de "kullanma". Makaleye baktim ve ne yazik ki katilmiyorum. Eger XML ile data gondereceksem daha efektif "openxml". Ornegin:

Visual Fox Pro
Local cXML, cNodeName, lnHandle,lcInsertSQL

 
TEXT to lcInsertSQL noshow
Declare @testTable table
(
    [CustomerId] [varchar](10),
    [CompanyName] [varchar](50),
    [ContactName] [varchar](50),
    [Country] [varchar](20)
);
 
-- XMLi bir tabloya select ve oradan insert islemi burada
 
DECLARE @hDoc int;
exec sp_xml_preparedocument @hDoc OUTPUT, ?m.cXML;
 
insert @testTable (CustomerId, CompanyName, ContactName, Country)
Select Cust_Id, Company, Contact, Country
FROM OPENXML(@hDoc, ?m.cNodename, 1)
WITH (cust_id varchar(10), company varchar(50),
       contact varchar(50), country varchar(20));
 
EXEC sp_xml_removedocument @hDoc;
 
-- XMLi bir tabloya select ve oradan insert islemi burada
-- Insert edilen datayi SQL serverdan al
select * from @testTable;
 
ENDTEXT
 
Select Cust_Id, Company, Contact, Country ;
    from (_samples+'data\Customer') ;
    into Cursor crsMyCustomers ;
    nofilter
 
Cursortoxml('crsMyCustomers','cXML',2,0,0,'1') && parametre 1 cXML
cNodeName = '/VFPData/crsmycustomers' && VFP default naming in XML - parametre 2 cNodeName
 
Close Databases all
 
lnHandle = Sqlstringconnect('driver={SQL Server Native Client 10.0};server=.\SQLExpress;Trusted_Connection=yes;')
 
SQLExec(m.lnHandle, m.lcInsertSQL,'crsSQLCustomers')
 
SQLDisconnect(0)
 
 
Select 'crsSQLCustomers'
Browse