olmayan kayıt nasıl bulunur

Firebird ve Interbase veritabanları ve SQL komutlarıyla ilgli sorularınızı sorabilirsiniz. Delphi tarafındaki sorularınızı lütfen Programlama forumunda sorunuz.
Cevapla
Kullanıcı avatarı
y.kulac
Üye
Mesajlar: 276
Kayıt: 08 Kas 2003 12:03
Konum: serdivan/sakarya

olmayan kayıt nasıl bulunur

Mesaj gönderen y.kulac »

s.a.
tabloda integer bir alan var ve 1 den başlayıp 300.000 e kadar sayı var.
aralarda olmayan sayılar var.
örneğin 300.000 kayıt arasında 1500 ile 2000 arası sayılar tabloya girilmedi.
benim amacım bu 300.000 kayıt içinde olmayan sayıları bulmak

Kod: Tümünü seç


sayi:=1;
ibdataset1.first;
while not ibdataset1.eof do
begin
if sayi <> ibdataset1.FieldByName('SAYINO').asinteger then
listbox1.items.Add(sayi);
sayi:=sayi+1;
ibdataset1.next;
end;


bu şekilde bir döngüyle alabilirm ama, 300.000 kayıt tek tek kontrol edilecek. buda bayağı bir zaman alıyor.
bunun daha basit ve kolay bir yolu var mıdır?
serkan
Üye
Mesajlar: 666
Kayıt: 10 Tem 2003 12:08
Konum: bursa

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen serkan »

slm.daha pratik yöntemi varmıdır bilmemde eğer bu 300.000 sayısı sabit ise sen düzgün sıralanmış yani tüm sayıları girilmiş başka bir tablo daha hazırla.excel ile hazırlayıp dataları alabilirsin...daha sonra kontrol edeceğin tablo adı: KARISIKSIRA,düzgün girilen tablonun adı: DUZGUNSIRA olsun..aşağıdaki kodla bulabilirsin..

Kod: Tümünü seç

select integeralan from DUZGUNSIRA where integeralan not in(select integeralan from KARISIKSIRA) order by integeralan
kolay gelsin..
Ali Erdoğan
Kıdemli Üye
Mesajlar: 1026
Kayıt: 11 Şub 2005 02:12
Konum: İstanbul

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen Ali Erdoğan »

Firebird "in" operatöründen sonraki dizinin 1200 elemanı aşmaması gerekiyor. O yüzden yukarıdaki yöntem kırılabilir.
Kullanıcı avatarı
aslangeri
Moderator
Mesajlar: 4322
Kayıt: 26 Ara 2003 04:19
Konum: Ankara
İletişim:

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen aslangeri »

s.a.
bir sp ile halledilebilir kanısındayım.
süre olarak ne kadar alır odan tam emin değilim ama yukardaki ilk yöntemden daha kısa süreceğini tahmin ediyorum( ilk yöntem ayrıca sağlıklı değil gibime geliyor)
kod yaklaşık şöyle bir şey olacak

Kod: Tümünü seç

var_sayino=1
for 
  select sayino from tablo
   where koşulu
  into :out_sayino
do begin
  if (:var_sayino<:out_sayino) then
   begin
     :out_sayino=:var_sayino;
     suspend;
  end
 :var_sayino=:var_sayino+1;
end;
böylelikle geriye sadece tabloda olmayan sayinolar dönecektir.
kolay gelsin.
Duyduğun Şeylerin Söylediklerim Olduğuna Eminim Ama
Anladığın Şeylerin Anlatmak İstediklerim Olduğuna Emin Değilim
Kullanıcı avatarı
y.kulac
Üye
Mesajlar: 276
Kayıt: 08 Kas 2003 12:03
Konum: serdivan/sakarya

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen y.kulac »

en son şöyle bir yöntem denedim.

Kod: Tümünü seç

var sayi1,sayi2 : integer;

sayi1 :=1;
sayi2:=300000; // tablodaki sayı farzedelim.

while sayi1 < sayi2 do
begin
ibquery1.close;
ibquery1.sql.clear;
ibquery1.sql.add('select SAYINO From TABLO');
ibquery1.sql.add('Where SAYIN0 = '''+inttostr(sayi1)+'''');
ibquery1.open;
 if ibquery1.fieldbyname('SAYINO').asinteger > 0 then
 listbox1.items.add('inttostr(ibquery1.fieldbyname('SAYINO').asinteger));
sayi1:=sayi1+1;
end;
bu şekilde olmayan sayılar bulunuyor ama, böyle çok zaman alıyor. döngü içindeki kod 300.000 defa çalışıyor. program donuyor. veritabanına çok yük biniyor.

aslangeri kardeşiminin kodunu bir deneyeyim.
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen akdatilla »

MERHABA
ben şu şekilde bir çözüm ürettim.

aşağıdaki sp istenilen sayı aralığında değer üretiyor. İlk olarak bu sp'yi veritabanına eklemelisin.

Kod: Tümünü seç

 CREATE PROCEDURE SAYDIR (ILK INT,SON INT) RETURNS (SAYI INT)
 AS
 BEGIN
    SAYI=:ILK;
    WHILE (SAYI<=SON) DO
    BEGIN
       SUSPEND;
       SAYI=:SAYI+1;
    END
 END
daha sonra asıl sorunun cevabını olan "olmayan kayıtların listelenmesi"ni şöyle yapabiliriz":

Kod: Tümünü seç

SELECT * FROM SAYDIR(1,3000) WHERE NOT EXISTS(SELECT * FROM tabloadi WHERE SAYI=tablo_kno_alani)
notlar:
1-Yukarıdaki komutu kendi tablona uydurman gerekecektir.
2-Komutlar Firebird 2.1 ile denenmiştir.
Hakan Can
Üye
Mesajlar: 634
Kayıt: 04 Mar 2005 04:27
Konum: Ankara

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen Hakan Can »

SP yazmadan direk SQL cümlesi ile şu şekilde istenen elde edilebilir:

Kod: Tümünü seç

SELECT
  T1.SAYI
FROM
 (
  SELECT
    T2.SAYI * 10 + T3.SAYI * 100 + T4.SAYI * 1000 + T5.SAYI * 10000 + T6.SAYI + 1 AS SAYI
  FROM RDB$DATABASE T1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T2 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T3 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T4 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T5 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T6 ON 1 = 1
 ) T1
WHERE T1.SAYI <= 30000 AND NOT EXISTS (SELECT T2.SAYI FROM MYTABLO T2 WHERE T2.SAYI = T1.SAYI)
ORDER BY T1.SAYI
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen akdatilla »

Hakan Can yazdı:SP yazmadan direk SQL cümlesi ile şu şekilde istenen elde edilebilir:

Kod: Tümünü seç

SELECT
  T1.SAYI
FROM
 (
  SELECT
    T2.SAYI * 10 + T3.SAYI * 100 + T4.SAYI * 1000 + T5.SAYI * 10000 + T6.SAYI + 1 AS SAYI
  FROM RDB$DATABASE T1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T2 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T3 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T4 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T5 ON 1 = 1
    INNER JOIN
     (
      SELECT 0 AS SAYI FROM RDB$DATABASE UNION
      SELECT 1 AS SAYI FROM RDB$DATABASE UNION
      SELECT 2 AS SAYI FROM RDB$DATABASE UNION
      SELECT 3 AS SAYI FROM RDB$DATABASE UNION
      SELECT 4 AS SAYI FROM RDB$DATABASE UNION
      SELECT 5 AS SAYI FROM RDB$DATABASE UNION
      SELECT 6 AS SAYI FROM RDB$DATABASE UNION
      SELECT 7 AS SAYI FROM RDB$DATABASE UNION
      SELECT 8 AS SAYI FROM RDB$DATABASE UNION
      SELECT 9 AS SAYI FROM RDB$DATABASE
     ) T6 ON 1 = 1
 ) T1
WHERE T1.SAYI <= 30000 AND NOT EXISTS (SELECT T2.SAYI FROM MYTABLO T2 WHERE T2.SAYI = T1.SAYI)
ORDER BY T1.SAYI
Hocam senin kodu denedim ancak pek uygun bulmuyorum doğrusu. :(
Sadece 40 satırlık bir tabloda olmayan kayıtları bulmak 15053ms sürdü. Aynı işlem saydır sp ile ilk denemede 32ms de yapılıyor.
Hakan Can
Üye
Mesajlar: 634
Kayıt: 04 Mar 2005 04:27
Konum: Ankara

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen Hakan Can »

Testi 40 kayıt için değil de 100 bin kayıt için yaparsan daha net sonuç gelir. Zira benim yazdığım SQL 100 bin kayıt için idi. Daha doğrusu en büyük değeri 100 bin olan.

Veyahut SQL cümlesindeki T3'den sonrasını kaldırıp tekrar test etmen gerekir. O zaman 0.1 saniye falan çıkacaktır. Zira biri 100 kayıt diğeri 100 bin kayıt döndürüyor.

Benim bilgisayarda 2 saniye kadar sürdüydü (30 bin kayıt için).

Gerçi o da oldukça fazla.

Farklı bir yaklaşım sunmak amacıyla örnek vermiştim.

Tabi görünen neden ise SP'lerin ANSI-SQL ile olan problemi. Yani veritabanından mümkün mertebe uzak durma çabası.

Aslında bu FireBird'ün biraz da yetersizliği ile ilgili. Zira aynı (adapte edilmiş) SQL cümlesi MS SQL'de çok daha kısa sürede çalışıyor. 0.1 saniyede falan.

Elbette: "Bu işlemi SP yazmadan direk SQL cümlesi ile nasıl yapabiliriz?" sorusuna cevap bulma inadı da perde gerisindeki asıl neden idi.

FireBird olsun MS SQL olsun şahsen SP vs. tüm ANSI-SQL düşmanı yaklaşımlardan uzak durmayı tercih ederim.

Misal bu konuda hız sorununu yine SP yazmadan küçük bir ara tablo ile halletmenin yolunu arardım.

Elbette ben her daim FireBird ile çalışmayı düşünüyorum veya başka veritabanlarına adapte etmek sorun olmaz diyorsanız SP yazmak belki de en kolay çözümdür.

İyi çalışmalar.
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: olmayan kayıt nasıl bulunur

Mesaj gönderen akdatilla »

tekrar merhaba
Hakan Can arkadaşımın dediği gibi testi yüksek kayıt sayılı tablolarda yapmak daha doğru.
Kayıt sayısı arttıkça daha fazla işlem yapılacaktır tabiki.
Bilgisayarımda yüklü demo versiyon Firebird Development studio adlı bir programın query analyzer formu var.
Bu formu kullanarak bazı testler yaptım.
Elimde yüksek kayıt sayılı tablo olmadığı için önce tek ID alanı olan bir tablo yaptım.
Tabloya kayıtları bir sp kullanarak ekledim:

Kod: Tümünü seç

CREATE PROCEDURE SAYIURET (ILK    Integer,
       SON    Integer,
       ARALIK Integer)
returns (ID Integer)
AS 

begin
    ID=:ILK;
    WHILE ((:ID<=:SON) and (:ARALIK>0)) DO
    BEGIN
       SUSPEND;
       ID=:ID+:ARALIK;
    END
end
Bu sp'yi aşağıdaki gibi birkaç defa (farklı aralıklarla) çalıştırdım:

Kod: Tümünü seç

INSERT INTO TESTTBL (ID) SELECT ID FROM SAYIURET(120001,150000,3)
yukarıdaki komut 2şer aralıklı olarak 120001'den 150000 e kadar sayıları tabloya ekliyor.
Bu teknikle 165668 kayıtlık bir tablo hazırladım.
Daha sonra bu testtbl içinde olmayan kayıtları bulmak için aşağıdaki komutlu çalıştırdım:

Kod: Tümünü seç

SELECT * FROM SAYDIR(1,500000) WHERE NOT EXISTS(SELECT * FROM TESTTBL WHERE SAYI=ID) 
Bu komutun çalıştırılması kullandığım analyzere göre 110ms sürdü. Ancak kaçtane kayıt olduğunu gridden tektek sayarak bulmak zor olacaktı :)
Onun için şöyle bir komutu çalıştırdım

Kod: Tümünü seç

SELECT count(*) FROM SAYDIR(1,500000) WHERE NOT EXISTS(SELECT * FROM TESTTBL WHERE SAYI=ID) 
bu komut ile tabloda 1..500000 arasında 334332 olmayan sayı kaydı olduğunu buldum.
Ancak bu komutun çalışması diğerinden oldukça uzun sürdü:5453ms

Evet bu şekilde sp ile yüksek kayıtlı tablolarda test sonuçlarını elde etmiş oldum.
Sonra aynı sonuçları hakancan arkadaşın sp kullanmadan yapma yöntemine göre deneyeyim dedim.
Komutu çalıştırdım ve biriki dakika bekledikten sonra bu formu doldurmaya devam ettim.
Halen komut sonlanmadı ne yazıkki :?

Benim aldığım sonuca göre sp kullanmak oldukça uygun görünüyor.
Yalnız test ettiğim ve burada söylemek istediğim bir unsur daha var.
Subquery içinde yüksek kayıtsayılı sonuç döndüren sp kullanmanın firebird içinde çok büyük performans kaybına sebep olduğunu gördüm.
Yukarıdaki testi testtbl gibi normal bir tablo yerine sonuç döndüren SAYIURET sp'sini kullandığımız zaman anormal derecede uzun sürede
sonuç alınıyor. Bunu ilk denediğimde birkaç dakikada sonuç almıştım. Birsonraki denememde bilgisayarı kapatarak ancak durdurabildim:)
Yani şu an için subquery içinde uzun kayıtsayılı değer döndüren sp kullanmaktan kaçınmanızı tavsiye ederim. Belki bir firebird'in
yazılım hatası da olabilir.
Cevapla