FB/IB'de SQLDialect'e göre alanların DataType tanımı nedir ?

Firebird ve Interbase veritabanları ve SQL komutlarıyla ilgli sorularınızı sorabilirsiniz. Delphi tarafındaki sorularınızı lütfen Programlama forumunda sorunuz.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

Şimdi deneme fırsatım oldu....

- Dialect 1'e göre olan SQL kodunu Temrin Fonksiyonuna işledim.
Tabloya göre alanların tiplerini doğru getiriyor...

Kod: Tümünü seç

Function FieldDetayi2(TabloAdi, AlanAdi:String):String;
Var
  Sayac : Integer;
begin
  with IBQuery2 do
  begin
    Close;
    Database := IBDatabase1;
    SQL.Clear;

    SQL.Add('/* Dialect 1 için tablo alanları bilgisi */                                     ');
    SQL.Add('SELECT b.RDB$FIELD_NAME, c.RDB$FIELD_TYPE, c.RDB$FIELD_SUB_TYPE, b.RDB$FIELD_ID,');
    SQL.Add('  c.RDB$FIELD_LENGTH, c.RDB$FIELD_SCALE,                                        ');
    SQL.Add('case                                                                            ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 07 then /* SMALLINT */                                ');
    SQL.Add('    case                                                                        ');
    SQL.Add('      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then      ');
    SQL.Add('        case when c.RDB$FIELD_SCALE = 0 then ''SMALLINT''                       ');
    SQL.Add('          else ''NUMERIC''                                                      ');
    SQL.Add('        end                                                                     ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 1 then ''NUMERIC''                            ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 2 then ''DECIMAL''                            ');
    SQL.Add('    end                                                                         ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 08 then /* INTEGER */                                 ');
    SQL.Add('    case                                                                        ');
    SQL.Add('      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then      ');
    SQL.Add('        case when c.RDB$FIELD_SCALE = 0 then ''INTEGER''                        ');
    SQL.Add('          else ''NUMERIC''                                                      ');
    SQL.Add('        end                                                                     ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 1 then ''NUMERIC''                            ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 2 then ''DECIMAL''                            ');
    SQL.Add('    end                                                                         ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 09 then ''QUAD''                                      ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 10 then ''FLOAT''                                     ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 11 then ''D_FLOAT''                                   ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 13 then ''TIME''                                      ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 14 then ''CHAR''                                      ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 27 then /* DOUBLE PRECISION */                        ');
    SQL.Add('    case                                                                        ');
    SQL.Add('      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then      ');
    SQL.Add('        case when c.RDB$FIELD_SCALE = 0 then ''DOUBLE PRECISION''               ');
    SQL.Add('          else ''NUMERIC''                                                      ');
    SQL.Add('        end                                                                     ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 1 then ''NUMERIC''                            ');
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 2 then ''DECIMAL''                            ');
    SQL.Add('    end                                                                         ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 35 then ''DATE''                                      ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 37 then ''VARCHAR''                                   ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 40 then ''CSTRING''                                   ');
    SQL.Add('  when c.RDB$FIELD_TYPE = 261 then ''BLOB''                                     ');
    SQL.Add('end                                                                             ');
    SQL.Add('FROM RDB$RELATIONS a                                                            ');
    SQL.Add('INNER JOIN RDB$RELATION_FIELDS b                                                ');
    SQL.Add('ON a.RDB$RELATION_NAME = b.RDB$RELATION_NAME                                    ');
    SQL.Add('INNER JOIN RDB$FIELDS c                                                         ');
    SQL.Add('ON b.RDB$FIELD_SOURCE = c.RDB$FIELD_NAME                                        ');
    SQL.Add('INNER JOIN RDB$TYPES d                                                          ');
    SQL.Add('ON c.RDB$FIELD_TYPE = d.RDB$TYPE                                                ');
    SQL.Add('WHERE a.RDB$SYSTEM_FLAG = 0                                                     ');
    SQL.Add('AND d.RDB$FIELD_NAME = ''RDB$FIELD_TYPE''                                       ');
    SQL.Add('  AND b.RDB$RELATION_NAME=' + QuotedStr(TabloAdi) );
    SQL.Add('  AND b.RDB$FIELD_NAME='    + QuotedStr(AlanAdi)  );
    SQL.Add('ORDER BY b.RDB$FIELD_ID                                                         ');

    Active := True;
    Result := Format('%s (%d)', [Trim(Fields[6].AsString), FieldByName('RDB$FIELD_LENGTH').AsInteger, Abs(FieldByName('RDB$FIELD_SCALE').AsInteger)]);
    Active := False;
  end; // With
end;
- İşler yoğunlaştı artık sık bakamıyorum. Bu günlük bu kadar... Sanıyorum başlık da finale erdi... :lol: :lol: :lol:

- Ayrıdığın vakit için ayrıca teşekkürler... 8)
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Aslında sonradan, makalelik birşey ortaya çıkabilir. Şu an için daha çok fikir üretiyor ve tartışıyoruz. :) Derli toplu bir hale getirebilirsek ileride herhalde @mrmcop veya ben bir makale hazırlarız.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Sonuca ulaşmamıza sevindim. Eğlenceli bişi bu hacking. Yine tekrarlayalım. :)
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Dialect 1 de TIME tipi olmadığından SQL kodundan çıkardım.
onaydin

Mesaj gönderen onaydin »

Tebrikler
Bende soyle birşeye rastladım, hemen hemen sizin yaklaşımınıza benzer şekilde bir sql yazmışlar hatta onlarda bu sql de numeric decimal olayını kurmaya çalışıyorlardı

Kod: Tümünü seç

SELECT
   rf.rdb$relation_name ,
   rf.rdb$field_name  ,
   CASE f.rdb$field_type
     WHEN 7 THEN
       CASE
         WHEN (COALESCE(f.rdb$field_sub_type, 0) = 0) THEN 'SMALLINT'
         WHEN (f.rdb$field_sub_type = 1) THEN 'NUMERIC' || '(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
         WHEN (f.rdb$field_sub_type = 2) THEN 'DECIMAL' || '(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
       ELSE
        'Unknown [7,' || f.rdb$field_sub_type ||']'
       END
     WHEN 8 THEN
       CASE
         WHEN (COALESCE(f.rdb$field_sub_type, 0) = 0) THEN 'INTEGER'
         WHEN (f.rdb$field_sub_type = 1) THEN 'NUMERIC' || '(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
         WHEN (f.rdb$field_sub_type = 2) THEN 'DECIMAL' || '(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
       ELSE
         'Unknown [8,' || f.rdb$field_type ||']'
       END
     WHEN 10 THEN 'FLOAT'
     WHEN 12 THEN 'DATE'
     WHEN 13 THEN 'TIME'
     WHEN 14 THEN 'CHAR(' || f.rdb$field_length || ')' || COALESCE(' CHARACTER SET ' ||
rdb$character_set_name, '')
     WHEN 16 THEN
       CASE
         WHEN (COALESCE(f.rdb$field_sub_type, 0) = 0) THEN 'BIGINT'
         WHEN (f.rdb$field_sub_type = 1) THEN 'NUMERIC' ||'(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
         WHEN (f.rdb$field_sub_type = 2) THEN 'DECIMAL' || '(' || f.rdb$field_precision ||
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')'
       ELSE
         'Unknown [16,' || f.rdb$field_type ||']'
       END
     WHEN 27 THEN 'DOUBLE PRECISION'
     WHEN 35 THEN 'TIMESTAMP'
     WHEN 37 THEN 'VARCHAR(' || f.rdb$field_length || ')' || COALESCE(' CHARACTER SET ' ||
rdb$character_set_name, '')
     WHEN 261 THEN 'BLOB SUB_TYPE ' || f.rdb$field_sub_type || ' SEGMENT SIZE ' ||
rdb$segment_length || COALESCE(' CHARACTER SET ' || rdb$character_set_name, '')
     ELSE 'Unknown [' || f.rdb$field_type ||']'
   END ||
   CASE WHEN (rf.rdb$null_flag IS NULL) THEN '' ELSE ' NOT NULL' END ||
   COALESCE(' COLLATE ' || c.rdb$collation_name,'')
 FROM
   rdb$relation_fields rf
   JOIN rdb$fields f ON (f.rdb$field_name = rf.rdb$field_source)
   LEFT JOIN rdb$field_dimensions fd ON (fd.rdb$field_name = f.rdb$field_name)
   LEFT JOIN RDB$CHARACTER_SETS cs ON (cs.rdb$character_set_id = f.rdb$character_set_id)
   LEFT JOIN RDB$COLLATIONS c ON (c.rdb$collation_id = rf.rdb$collation_id and
c.rdb$character_set_id = f.rdb$character_set_id)
 WHERE
   rf.rdb$relation_name = 'SALES'
 ORDER BY
   rf.rdb$relation_name, rf.rdb$field_position, fd.rdb$dimension
Dünyanın farklı yerinde farklı insanların benzer çözümler üretmeleri hatta burada bilgilerini bizlerle paylaşmaları beni birkez daha mutlu etti :)
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4741
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Mesaj gönderen mrmarman »

@coderlord Kızacaksın ama bir şeyi atlamışız...Resim

- Hazırladığın SQL cümlesini istisnası birebir query edip denedim ve sonucu NUMERIC görünce Resim sevinçten açılımına bakmamışım.

- Bu cümleyi biraz önce Delphi kod fonksiyonuna dönüştürüyordum. Ortaya şu tablo çıktı...

Kod: Tümünü seç

    SQL.Add('  when c.RDB$FIELD_TYPE = 08 then /* INTEGER */                                 '); 
    SQL.Add('    case                                                                        '); 
    SQL.Add('      when (c.RDB$FIELD_SUB_TYPE = 0 or c.RDB$FIELD_SUB_TYPE is null) then      '); 
    SQL.Add('        case when c.RDB$FIELD_SCALE = 0 then ''INTEGER''                        '); 
    SQL.Add('          else ''NUMERIC''                                                      '); 
    SQL.Add('        end                                                                     '); 
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 1 then ''NUMERIC''                            '); 
    SQL.Add('      when c.RDB$FIELD_SUB_TYPE = 2 then ''DECIMAL''                            '); 
    SQL.Add('    end                                                                         '); 
iken ...
P.S. Değişiklik olarak tam kontrol adına Null kontrolü de yapmak için Sub_Type'ı field olarak fonksiyona yönelttim..

Kod: Tümünü seç

Function  TipDetayi(Field_Type:Integer; Field_Sub_Type: TField; Field_Length, Field_Precision, Field_Scale : Integer ) : String;
begin
  Result := '';
  Case Field_Type OF
    8 : // 'INTEGER';
        If (FIELD_SUB_TYPE.AsInteger = NULL) or (FIELD_SUB_TYPE.AsInteger = 0)
        then      Case FIELD_SCALE of
                  0 :  Result := 'INTEGER';
                  else Result := 'NUMERIC';
                  end // Case
        else
                  Case FIELD_SUB_TYPE.AsInteger of
                  1 : Result := 'NUMERIC';
                  2 : Result := 'DECIMAL';
                  end; // Case
  end; // Case
  Result := Format('%s /* (Tip:%d, SubType:%d) */',[Result, Field_Type, Field_Sub_Type.AsInteger] );
end;
- Hocam Dialect 1 örneğinde Type 8'e ait sonuç 0 veya NULL ise direkt base Type (burada INTEGER) diğer hallerde NUMERIC demişsin. :oops: Dialect 3 örneğinde Scale kontrolü yaptırıp yine direkt NUMERIC demişsin. :oops: Yani SUB_TYPE değeri yoksa ya base Type olan INTEGER ya da scale içeriyorsa NUMERIC oluyor.

- Biz bunu ilk sorduğum yapıda sadece DECIMAL olan yeri (EMS, IBExpert'e atıfta bulunduğum comment eklediğim satırlar) alıp yerine NUMERIC yazınca yapay olup olmadığını, belli bir kuralı varmıyı tartışıyorduk. Resim

- Bunu bir masaya yatıralım Resim

@onaydın Hocam konuyu sen de bir irdeler misin ?

Senin bulduğun kodun aşağıdaki kısmını Trace eder misin ? Büyük bir ihtimalle UnKnown çıkacak gibi ama bunu bir çalıştırabilirsen sevinirim.

Veritabanı : EMPLOYEE.GDB (Dialect 1)
Tablo : SALES
Alan Adı : TOTAL_VALUE
açılımı da
Type : 8
Sub_Type : 0
Scale : -2

Kod: Tümünü seç

     WHEN 8 THEN 
       CASE 
         WHEN (COALESCE(f.rdb$field_sub_type, 0) = 0) THEN 'INTEGER' 
         WHEN (f.rdb$field_sub_type = 1) THEN 'NUMERIC' || '(' || f.rdb$field_precision || 
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')' 
         WHEN (f.rdb$field_sub_type = 2) THEN 'DECIMAL' || '(' || f.rdb$field_precision || 
',' || CAST( -f.rdb$field_scale AS varChar(2)) || ')' 
       ELSE 
         'Unknown [8,' || f.rdb$field_type ||']' 
       END 
Resim
Resim ....Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

:) Ben bu tip alanlara cins alanlar adı verdim. Bir dökümanda IB 5.0 zamanında sub type falan yokmuş, adamlar numeric mi değil mi scale e bakarak anlıyorlarmış gibi birşey okumuştum. Employee.gdb de böyle birşey ile karşılaşınca ve IBExpert NUMERIC deyince ben de NUMERIC dedim. Zannedersem yine IB 5 zamanında sadece NUMERIC alan varmış ve IBExpert bu yüzden böyle gördüğüne, işte bu IB 5 zamanından kalma ve NUMERIC bir alan diyor. Uygulamada böyle alanlar ile karşılaşılacağını pek sanmıyorum.
Cevapla