Bir liste bir veritabanı tablosunun bir sütununda nasıl saklanır


117

Yani, başına ilgili soruya Mehrdad cevabı , ben bunu elde bir "doğru" veritabanı tablosu sütun listesini saklamak gelmez. Bunun yerine, söz konusu listenin öğelerini etkili bir şekilde tutan başka bir tablo oluşturmalı ve ardından ona doğrudan veya bir bağlantı tablosu aracılığıyla bağlanmalısınız. Ancak, oluşturmak istediğim liste türü benzersiz öğelerden oluşacaktır (bağlantılı sorunun meyvesimisal). Ayrıca, listemdeki öğeler açıkça sıralanmıştır - bu, öğeleri başka bir tabloda depolamışsam, onlara her eriştiğimde onları sıralamak zorunda kalacağım anlamına gelir. Son olarak, liste temelde atomiktir, çünkü ne zaman listeye erişmek istersem, listenin bir parçası yerine tüm listeye erişmek isteyeceğim - bu yüzden, parçalarını bir araya getirmek için bir veritabanı sorgusu yayınlamak zorunda olmak aptalca görünüyor. liste.

AKX'in çözümü (yukarıda bağlantılı) listeyi seri hale getirmek ve ikili bir sütunda saklamaktır. Ama bu aynı zamanda uygunsuz görünüyor çünkü serileştirme ve seriyi kaldırma konusunda endişelenmem gerektiği anlamına geliyor.

Daha iyi bir çözüm var mı? Eğer orada olduğunu daha iyi bir çözüm o zaman neden? Görünüşe göre bu problem zaman zaman ortaya çıkmalı.

... nereden geldiğimi size bildirmek için biraz daha bilgi. SQL'i ve genel olarak veritabanlarını anlamaya yeni başlar başlamaz, LINQ to SQL'e yönlendirildim ve bu yüzden şimdi biraz şımarıkım çünkü nesnelerin nasıl olduğunu düşünmek zorunda kalmadan programlama nesne modelimle ilgilenmeyi umuyorum. sorgulanır veya veritabanında saklanır.

Hepinize teşekkürler!

John

GÜNCELLEME: Aldığım ilk cevap telaşında, "CSV / XML yoluna gidebilirsiniz ... ama YAPMAYIN!" Görüyorum. Bu yüzden şimdi nedeninin açıklamalarını arıyorum. Beni bazı iyi referanslara yönlendirin.

Ayrıca, neyin peşinde olduğum hakkında size daha iyi bir fikir vermesi için: Veritabanımda (x, y) çiftlerinin bir listesini içeren bir İşlev tablosuna sahibim. (Tabloda ayrıca tartışmamız açısından önemi olmayan başka bilgiler de olacaktır.) (X, y) çiftleri listesinin bir kısmını asla görmeye ihtiyacım olmayacak. Bunun yerine hepsini alıp ekrana çizeceğim. Kullanıcıların zaman zaman değerleri değiştirmek veya grafiğe daha fazla değer eklemek için düğümleri sürüklemesine izin vereceğim.

Yanıtlar:


183

Hayır, bir dizi öğeyi tek bir sütunda saklamanın "daha iyi" bir yolu yoktur. İlişkisel veritabanları, satır / sütun kombinasyonu başına bir değer depolamak için özel olarak tasarlanmıştır . Birden fazla değeri depolamak için, listenizi depolama için tek bir değerde serileştirmeniz ve ardından geri alındığında seri durumdan çıkarmanız gerekir . Bahsettiğiniz şeyi yapmanın başka yolu yoktur (çünkü bahsettiğiniz şey, genel olarak asla yapılmaması gereken kötü bir fikirdir ).

Bu listeyi depolamak için başka bir tablo oluşturmanın aptalca olduğunu düşündüğünüzü anlıyorum, ancak ilişkisel veritabanlarının yaptığı tam olarak budur. Yokuş yukarı bir savaşta savaşıyorsunuz ve iyi bir sebep olmaksızın ilişkisel veritabanı tasarımının en temel ilkelerinden birini ihlal ediyorsunuz. SQL'i yeni öğrendiğinizi belirttiğiniz için, bu fikirden kaçınmanızı ve daha deneyimli SQL geliştiricileri tarafından size önerilen uygulamalara bağlı kalmanızı şiddetle tavsiye ediyorum.

İhlal ettiğiniz ilkeye , veritabanı normalleştirmesinin ilk adımı olan ilk normal biçim denir .

Şeyi basitleştirerek riskini göze alarak, veritabanı normalleştirme veri gördüğü sorunlara dayalı veritabanınızı tanımlama sürecidir olduğunu buna karşı duyarlı, tutarlı sorguları yazmak ve kolayca korumak mümkün olabilir böylece. Normalleştirme, verilerinizdeki mantıksal tutarsızlıkları ve bozulmaları sınırlandırmak için tasarlanmıştır ve bunun birçok düzeyi vardır. Veritabanı normalleştirme hakkındaki Wikipedia makalesi aslında oldukça iyidir.

Temel olarak, normalleştirmenin ilk kuralı (veya formu) tablonuzun bir ilişkiyi temsil etmesi gerektiğini belirtir. Bunun anlamı şudur ki:

  • Bir satırı diğer herhangi bir satırdan ayırt edebilmeniz gerekir (başka bir deyişle, tablonuzun birincil anahtar olarak hizmet edebilecek bir şeye sahip olması gerekir . Bu aynı zamanda hiçbir satırın kopyalanmaması gerektiği anlamına gelir.
  • Verilerin herhangi bir sıralaması, satırların fiziksel sıralamasıyla değil verilerle tanımlanmalıdır (SQL, bir küme fikrine dayanır, yani güvenmeniz gereken tek sıralama, sorgunuzda açıkça tanımladığınız şeydir)
  • Her satır / sütun kesişimi bir ve yalnızca bir değer içermelidir

Son nokta, buradaki dikkat çekici noktadır. SQL, bir seti kendiniz saklamanız için size bir "kova" sağlamak için değil, sizin için setlerinizi depolamak üzere tasarlanmıştır. Evet yapmak mümkün. Hayır, dünyanın sonu gelmeyecek. Bununla birlikte, hemen bir ORM kullanmaya başlayarak SQL'i ve onunla birlikte gelen en iyi uygulamaları anlama konusunda kendinizi çoktan sakatladınız. LINQ to SQL harika, tıpkı grafik hesap makineleri gibi. Aynı şekilde, ancak, gerektiği değil süreçler aslında işi istihdam bilerek için bir yedek olarak kullanılabilir.

Listeniz şu anda tamamen "atomik" olabilir ve bu, bu proje için değişmeyebilir. Ancak, yine de, diğer projelerde benzer şeyler yapma alışkanlığı kazanacaksınız ve sonunda (büyük olasılıkla hızlı bir şekilde), şimdi bir sütundaki hızlı ve kolay listenizi uydurduğunuz bir senaryo ile karşılaşacaksınız. tamamen uygunsuz olduğu durumlarda yaklaşım. Depolamaya çalıştığınız şey için doğru tabloyu oluşturmak için çok fazla ek çalışma yoktur ve veritabanı tasarımınızı gördüklerinde diğer SQL geliştiricileri tarafından alay edilmeyeceksiniz. Ayrıca LINQ to SQL, ilişkinizi görecek ve size listeniz için uygun nesne odaklı arayüzü otomatik olarak verecektir . Standart olmayan ve kötü tavsiye edilen veritabanı korsanlığı yapabilmeniz için ORM'nin size sunduğu kolaylıktan neden vazgeçiyorsunuz?


17
Bu nedenle, bir listeyi bir sütunda saklamanın kötü bir fikir olduğuna şiddetle inanıyorsunuz, ancak nedenini belirtmekte başarısız oluyorsunuz. SQL ile yeni başladığım için, biraz "neden" gerçekten çok yardımcı olacaktır. Örneğin, "zorlu bir savaşta mücadele ettiğimi ve ilişkisel veritabanı tasarımının en temel ilkelerinden birini haksız yere ihlal ettiğimi" söylüyorsunuz ... peki bu ilke nedir? Neden "iyi değil" dediğim nedenler? (özellikle listelerimin sıralı ve atomik yapısı)
JnBrymn

6
Temel olarak, en iyi uygulamalara yoğunlaştırılmış yılların deneyimine bağlıdır. Söz konusu temel prensip, 1. Normal Form olarak bilinir .
Toby

1
Teşekkürler Adam. Çok bilgilendirici. Son sorunuz için iyi bir nokta.
JnBrymn

8
"[…] Ve veritabanı tasarımınızı gördüklerinde diğer SQL geliştiricileri tarafından alay edilmeyeceksiniz." Orada Birinci Normal Form (ve cevabı onları bahseder) saygı çok iyi nedenleri vardır, ancak “şeyler burada işler nasıl var” mahalle baskısı / olduğu değil aralarında.
Lynn

5
Zaten her gün veritabanı sütunlarında bir sürü liste saklıyoruz. "Char" ve "varchar" olarak adlandırılırlar. Elbette Postgres'te bunlara metin de denir. 1NF'nin gerçekten söylediği şey, herhangi bir alandaki bilgileri daha küçük alanlara bölmek istememeniz gerektiğidir ve bunu yaparsanız, aptallık etmiş olursunuz. Böylece adı saklamazsınız, kişisel adınızı, ikinci adlarınızı ve soyadlarınızı (yerelleştirmeye bağlı olarak) saklar ve bunları bir araya getirirsiniz. Aksi takdirde metin dizelerini hiç saklamazdık. Öte yandan, tek istediği bir dizi dizgidir. Ve bunu yapmanın yolları var.
Haakon Løtveit

15

SQL'i hep birlikte unutabilir ve "NoSQL" yaklaşımıyla gidebilirsiniz. RavenDB , MongoDB ve CouchDB , olası çözümler olarak akla geliyor. Bir NoSQL yaklaşımı ile, ilişkisel modeli kullanmıyorsunuz .. hatta şemalarla sınırlı değilsiniz.


11

Birçok insanın yaptığını gördüğüm şey şudur (en iyi yaklaşım olmayabilir, yanılıyorsam düzeltin):

Örnekte kullandığım tablo aşağıda verilmiştir (tablo, belirli kız arkadaşlarınıza vermiş olduğunuz takma adları içerir. Her kız arkadaşın benzersiz bir kimliği vardır):

nicknames(id,seq_no,names)

Bir id altında birçok takma ad saklamak istediğinizi varsayalım. Bu yüzden bir seq_noalan dahil ettik .

Şimdi bu değerleri tablonuza doldurun:

(1,1,'sweetheart'), (1,2,'pumpkin'), (2,1,'cutie'), (2,2,'cherry pie')

Kız arkadaşınızın kimliği 1'e verdiğiniz tüm isimleri bulmak istiyorsanız kullanabilirsiniz:

select names from nicknames where id = 1;

5

Basit cevap: Listenin her zaman bir liste olarak kullanılacağından eminseniz ve yalnızca listenin sonunda kullanılmayacak bir karakterle ('\ 0' gibi) listeyi birleştirin. hiç metin ve sakla. Sonra onu geri aldığınızda, '\ 0' ile bölebilirsiniz. Elbette bu konuda başka yollar da var, ancak bunlar sizin özel veritabanı satıcınıza bağlıdır.

Örnek olarak, JSON'u bir Postgres veritabanında depolayabilirsiniz. Listeniz metinse ve listeyi daha fazla uğraşmadan istiyorsanız, bu makul bir uzlaşmadır.

Diğerleri serileştirme önerileri geliştirdiler, ancak serileştirmenin iyi bir fikir olduğunu gerçekten düşünmüyorum: Veritabanları hakkındaki en güzel şey, farklı dillerde yazılmış birkaç programın birbiriyle konuşabilmesidir. Ve Java'nın formatı kullanılarak serileştirilen programlar, bir Lisp programı onu yüklemek isteseydi o kadar da iyi olmazdı.

Bu tür bir şeyi yapmanın iyi bir yolunu istiyorsanız, genellikle dizi veya benzeri türler mevcuttur. Örneğin Postgres, bir tür olarak dizi sunar ve istediğiniz şey buysa bir dizi metin depolamanıza olanak tanır ve JSON kullanan MySql ve MS SQL için benzer hileler vardır ve IBM'in DB2'si de bir dizi türü sunar (kendi kendi yararlı ) belgelerine. Buna ihtiyaç olmasaydı bu çok yaygın olmazdı.

O yola girerek kaybettiğiniz şey, sırayla bir sürü şey olarak liste kavramıdır. En azından nominal olarak, veritabanları alanları tek değerler olarak ele alır. Ama tek istediğin buysa, o zaman gitmelisin. Kendiniz için yapmanız gereken bir değer yargısıdır.


3

Herkesin söylediklerine ek olarak, yaklaşımınızı şimdi olduğundan daha uzun vadede analiz etmenizi öneririm. Öyle anda ürün benzersiz olmasını durumda. Öyle anda öğeleri başvurmadan yeni bir liste gerektirecektir bu durumda. Listenin şu anda kısa olması neredeyse gerekiyor . Alan bilgilerine sahip olmasam da, bu gereksinimlerin değişebileceğini düşünmek pek de zor değil. Listenizi seri hale getirirseniz, daha normalize edilmiş bir tasarımda gerekli olmayan bir esneklik içinde pişiyorsunuz demektir. Btw, bu mutlaka tam bir Many: Pek çok ilişki anlamına gelmez. Üst öğeye yabancı anahtarı olan tek bir alt tablonuz ve öğe için bir karakter sütununuz olabilir.

Yine de listeyi serileştirme yolunda ilerlemek istiyorsanız, listeyi XML'de saklamayı düşünebilirsiniz. SQL Server gibi bazı veritabanlarının bir XML veri türü bile vardır. XML'i önermemin tek nedeni, neredeyse tanım gereği bu listenin kısa olması gerektiğidir. Liste uzunsa, genel olarak serileştirmek kötü bir yaklaşımdır. CSV yoluna giderseniz, sınırlayıcıyı içeren değerleri hesaba katmanız gerekir, bu da alıntılanmış tanımlayıcıları kullanmak zorunda olduğunuz anlamına gelir. Listelerin kısa olduğunu varsayarsak, CSV veya XML kullanmanız muhtemelen pek bir fark yaratmayacaktır.


Gelecekteki değişiklikleri tahmin etmek için +1 - veri modelinizi her zaman genişletilebilir olacak şekilde tasarlayın.
coolgeek

2

Sadece CSV olarak saklardım, eğer basit değerler ise, ihtiyacınız olan tek şey olmalıdır (XML çok ayrıntılıdır ve ona doğru / ondan serileştirme muhtemelen abartılı olur, ancak bu da bir seçenek olabilir).

İşte bu iyi bir cevap LINQ ile CSV'leri çekmeyi nasıl.


Bunu düşündüm. Yine de seri hale getirmem ve seriyi kaldırmam gerektiği anlamına geliyor ... ama bunun yapılabilir olduğundan şüpheleniyorum. Keşke istediğimi yapmanın göz yumulmuş bir yolu olsaydı , ama olmadığından şüpheleniyorum.
JnBrymn

capnproto.org , capnproto'nun seçtiğiniz dilde desteklenmemesi durumunda, benzer şekilde hızlı (csv veya xml ile karşılaştırıldığında) serileştirmek ve seriyi kaldırmak zorunda kalmamanın bir yoludur msgpack.org/index.html
VoronoiPotato,

2

Listede sorgulama yapmanız gerekiyorsa, bir tabloya kaydedin.

Listeyi her zaman istiyorsanız, bir sütunda ayrılmış liste olarak saklayabilirsiniz. Bu durumda bile, ÇOK belirli nedenleriniz yoksa, bir arama tablosunda saklayın.


1

Cevaplarda sadece bir seçenek belirtilmemiştir. DB tasarımınızı normalleştirebilirsiniz. Yani iki masaya ihtiyacınız var. Bir tablo, her satırda bir öğe olmak üzere uygun liste içerir, başka bir tablo, bir sütunda tüm listeyi içerir (örneğin, virgülle ayrılmış).

İşte 'geleneksel' DB tasarımı:

List(ListID, ListName) 
Item(ItemID,ItemName) 
List_Item(ListID, ItemID, SortOrder)

İşte normalleştirilmiş tablo:

Lists(ListID, ListContent)

Buradaki fikir - tetikleyicileri veya uygulama kodunu kullanarak Listeler tablosunu korursunuz. List_Item içeriğini her değiştirdiğinizde, Listelerdeki uygun satırlar otomatik olarak güncellenir. Çoğunlukla listeleri okursanız, oldukça iyi çalışabilir. Artıları - listeleri tek bir ifadede okuyabilirsiniz. Eksileri - güncellemeler daha fazla zaman ve çaba gerektirir.


0

Eğer gerçekten bir sütunda saklamak ve sorgulanabilir olmasını istiyorsanız, birçok veritabanı artık XML'i desteklemektedir. Sorgulamıyorsanız, bunları virgülle ayrılmış değerler olarak saklayabilir ve ihtiyaç duyduğunuzda bir işlevle ayrıştırabilirsiniz. Diğer herkesle aynı fikirdeyim, ancak ilişkisel bir veritabanı kullanmak istiyorsanız, normalleştirmenin büyük bir kısmı verilerin bu şekilde ayrılmasıdır. Yine de tüm verilerin ilişkisel bir veritabanına uyduğunu söylemiyorum. Verilerinizin çoğu modele uymuyorsa, her zaman diğer veritabanı türlerine bakabilirsiniz.


0

Bazı durumlarda, veri tabanında SAHTE bir öğe "listesi" oluşturabileceğinizi düşünüyorum, örneğin, malın ayrıntılarını göstermek için birkaç resmi vardır, resimlerin tüm kimliklerini virgülle bölerek birleştirebilir ve diziyi DB ise, ihtiyacınız olduğunda dizeyi ayrıştırmanız yeterlidir. Şu anda bir web sitesi üzerinde çalışıyorum ve bu şekilde kullanmayı planlıyorum.


0

Pek çok cevap yüzünden nihayet seçmeye karar verdiğim yolu seçmekte çok isteksizdim. SQL'in ne olduğunu ve ilkelerini daha iyi anlamalarını sağlarken ben de kanun kaçağı olmaya karar verdim. Bulgularımı yayınlamakta da tereddüt ettim, çünkü bazıları için çok az evrensel gerçek olduğunu anlamaktan ziyade kuralları çiğneyen birine hayal kırıklığını ifade etmek daha önemli.

Kapsamlı bir şekilde test ettim ve benim özel durumumda, hem dizi türünü (PostgreSQL tarafından cömertçe sunulur) hem de başka bir tabloyu sorgulamaktan çok daha verimli oldu.

İşte cevabım: Listenin her bir öğesinin sabit uzunluğunu kullanarak bir listeyi PostgreSQL'de tek bir alana başarıyla uyguladım. Her öğenin ARGB onaltılık değeri olarak bir renk olduğunu varsayalım, 8 karakter anlamına gelir. Böylece, her bir öğenin uzunluğuyla çarparak en fazla 10 öğe dizisi oluşturabilirsiniz:

ALTER product ADD color varchar(80)

Liste öğelerinizin uzunluğu farklıysa, dolguyu her zaman \ 0 ile doldurabilirsiniz

Not: Açıkçası bu, onaltılık sayı için en iyi yaklaşım değildir, çünkü bir tamsayılar listesi daha az depolama tüketir, ancak bu, her bir öğeye tahsis edilmiş sabit bir uzunluktan yararlanarak bu dizi fikrini göstermek içindir.

Nedeni: 1 / Çok kullanışlı: i öğesini i * n, (i +1) * n alt dizesinde geri alın. 2 / Çapraz tablo sorgularının ek yükü yok. 3 / Sunucu tarafında daha verimli ve düşük maliyetli. Liste, müşterinin bölmek zorunda kalacağı bir mini blob gibidir.

Kurallara uyan insanlara saygı duysam da, pek çok açıklama çok teoriktir ve bazı özel durumlarda, özellikle düşük gecikmeli çözümlerle optimum maliyeti hedeflerken, bazı küçük ayarların hoş karşılanmayacağını kabul etmekte başarısız olur.

"Tanrı, SQL'in bazı kutsal kutsal ilkelerini ihlal ettiğini korusun": Kuralları okumadan önce daha açık fikirli ve pragmatik bir yaklaşım benimsemek her zaman gitmenin yoludur. Aksi takdirde , Skynet tarafından yok edilmeden önce Robotiklerin Üç Yasasını okuyan samimi bir fanatik gibi olabilirsiniz.

Bu çözümün bir buluş olduğunu veya okunabilirlik ve veritabanı esnekliği açısından ideal olduğunu iddia etmiyorum, ancak gecikme söz konusu olduğunda kesinlikle size bir avantaj sağlayabilir.


Ancak bu çok özel bir durumdur: sabit sayıda sabit uzunlukta parça. O zaman bile, standart SQL'den daha zor "en az renk x'e sahip tüm ürünler" gibi basit bir arama yapar.
Gert Arnold

Birçok kez belirttiğim gibi, onu renk için kullanmıyorum, kullandığım alan indekslenmemeli veya bir koşul olarak kullanılmamalı ve yine de kritik bir konu
Antonin GAVREL

Biliyorum, bunun oldukça spesifik olduğunu belirtmeye çalışıyorum. Herhangi bir küçük ek gereksinim gizlice girerse, standart çözümlere göre hızla daha garip hale gelir. Listeleri tek bir db alanında saklamak isteyen insanların büyük çoğunluğu muhtemelen bunu yapmamaktan daha iyidir.
Gert Arnold

0

Çoğu SQL veritabanı, bir tablonun bileşen olarak bir alt tablo içermesine izin verir. Genel yöntem, sütunlardan birinin etki alanının tablo olmasına izin vermektir. Bu, alt yapıyı DBMS tarafından bilinmeyen şekillerde kodlamak için CSV gibi bazı konvansiyonların kullanılmasına ilavedir.

Ed Codd, ilişkisel modeli 1969-1970'de geliştirirken, özellikle bu tür tabloların iç içe geçmesine izin vermeyecek normal bir form tanımladı . Normal forma daha sonra Birinci Normal Form adı verildi. Daha sonra, her veritabanı için, aynı bilgiyi ifade eden ilk normal formda bir veritabanı olduğunu göstermeye devam etti.

Neden bununla uğraşıyorsun? İlk normal formdaki veritabanları, tüm verilere anahtarlı erişime izin verir. Bir tablo adı, bu tabloya bir anahtar değer ve bir sütun adı sağlarsanız, veritabanı bir veri öğesi içeren en fazla bir hücre içerecektir.

Bir hücrenin bir liste veya tablo veya başka bir koleksiyon içermesine izin verirseniz, artık bir anahtar fikrini tamamen yeniden çalışmadan alt öğelere anahtarlı erişim sağlayamazsınız.

Tüm verilere anahtarlı erişim, ilişkisel model için temeldir. Bu konsept olmadan model ilişkisel değildir. İlişkisel modelin neden iyi bir fikir olduğuna ve bu iyi fikrin sınırlamalarının ne olabileceğine gelince, ilişkisel modelle 50 yıllık birikmiş deneyime bakmanız gerekir.


-1

bunu bir liste gibi görünen metin olarak saklayabilir ve verilerini gerçek bir liste olarak döndürebilen bir işlev oluşturabilirsiniz. misal:

veri tabanı:

 _____________________
|  word  | letters    |
|   me   | '[m, e]'   |
|  you   |'[y, o, u]' |  note that the letters column is of type 'TEXT'
|  for   |'[f, o, r]' |
|___in___|_'[i, n]'___|

Ve liste derleyici işlevi (python ile yazılmıştır, ancak diğer programlama dillerinin çoğuna kolayca çevrilebilir). METİN, sql tablosundan yüklenen metni temsil eder. listeyi içeren dizeden dizelerin listesini döndürür. dizeler yerine ints döndürmesini istiyorsanız, modu 'int'e eşit yapın. Aynı şekilde 'string', 'bool' veya 'float' ile.

def string_to_list(string, mode):
    items = []
    item = ""
    itemExpected = True
    for char in string[1:]:
        if itemExpected and char not in [']', ',', '[']:
            item += char
        elif char in [',', '[', ']']:
            itemExpected = True
            items.append(item)
            item = ""
    newItems = []
    if mode == "int":
        for i in items:
            newItems.append(int(i))

    elif mode == "float":
        for i in items:
            newItems.append(float(i))

    elif mode == "boolean":
        for i in items:
            if i in ["true", "True"]:
                newItems.append(True)
            elif i in ["false", "False"]:
                newItems.append(False)
            else:
                newItems.append(None)
    elif mode == "string":
        return items
    else:
        raise Exception("the 'mode'/second parameter of string_to_list() must be one of: 'int', 'string', 'bool', or 'float'")
    return newItems

Ayrıca, ihtiyacınız olması durumunda list-to-string işlevi de burada.

def list_to_string(lst):
    string = "["
    for i in lst:
        string += str(i) + ","
    if string[-1] == ',':
        string = string[:-1] + "]"
    else:
        string += "]"
    return string
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.