64

Is there any way to store an array of integers in one column of table? I want o/p like this:

ident | value                                                            | count 
----------------+------------------------------------------------------------------------------------------------------------------------+-------
563 | [0:10]={"(0,0)","(1,100)","(2,200)","(3,300)","(4,400)","(5,500)"} |    6

This I have already acheieved through postgres but i want same o/p from sqlite also. Here column value store an array. I tried it through BLOB but it is not working. Somebody told me about serialized way but i am not sure how to do that.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
SPK
  • 641
  • 1
  • 5
  • 3

7 Answers7

42

SQLite3 does not support arrays directly. See here the type it supports. Basically, it only does Ints, Floats and Text.

To accomplish what you need, you have to use a custom encoding, or use an FK, i.e. create another table, where each item in the array is stored as a row.

Gianni
  • 4,300
  • 18
  • 24
  • 3
    And then you import them into the original table as not an array? For example, you have 'referenced pages', right? Should be an array. And you have 'source document id'. So, how do you correlate the referenced pages to the appropriate source document id? I think that you actually have a second table which stores each item in the array against the first table's primary key, and a third row to indicate the relationship set, right? Can you check my answer? – Wolfpack'08 Nov 07 '12 at 09:54
33

SQLite has no support for arrays, so you can't store them as such. Instead of storing array elements individually, you can store them as a single string and use a string function or regular expression to parse them back into their types.

A C# example:

int[] myArray = new int[] {8,4,345,378,34456,7};

string Arraystring = myArray[0].ToString();

for(int i = 1; i < myArray.Length; i++) { 
    Arraystring += "," + myArray[i].ToString();
}

This will turn the array into a single string, now insert it as string. To get the array back:

string value; //assign this via Reader
string[] tokens = values.Split(',');

int[] myItems = Array.ConvertAll<string, int>(tokens, int.Parse);

This will only work with single dimensional arrays, multi-dimensional can get tricky when it comes to parsing the strings.

user4157124
  • 2,809
  • 13
  • 27
  • 42
Fornoreason1000
  • 395
  • 3
  • 9
  • 26
    If you are going this route why not store it as a json object since it is easy to go back and forth from json to most languages. – melston Jun 25 '17 at 14:49
  • 5
    Serializing objects to strings to store in SQLite database is ok if you can afford missing out on structured queries. – weaknespase Nov 17 '18 at 20:43
  • 1
    If you're going to do this is makes more sense to store them in binary format rather than as CSV, which will be quite inefficient. E.g. [prefixvarint](https://github.com/stoklund/varint#prefixvarint). – Timmmm Aug 27 '20 at 13:27
10

Sqlite now has native support for json_object() data types since version 3.38:

You can store arrays in a JSON field, query them, and index them. More info is here: https://www.sqlite.org/json1.html.

For example, ask which guests like oranges:

create table guests (name, likes);
insert into guests values ('bob', json('["apples", "oranges"]'));
insert into guests values ('alice', json('["oranges", "pears"]'));
insert into guests values ('carol', json('["apples", "pears"]'));
select name from guests, json_each(likes) where json_each.value='oranges';

You can try it out here: https://sqlime.org/#deta:m97q76wmvzvd

Erik Aronesty
  • 11,620
  • 5
  • 64
  • 44
6

You could use JSON.stringify and when you read in the data again JSON.parse. So you store an array as string and can easily parse it again back to an array. This way you can also put arrays of arrays into the sqlite db

Julian
  • 334
  • 4
  • 18
2

This is one way of serializing and deserializing data:

#include <string>
#include <vector>
#include <sstream>
#include <iostream>

std::vector<std::string> deserialize_array(std::string const &csv)
{
  std::istringstream parse(csv);
  std::vector<std::string> ret;
  for(std::string token; std::getline(parse, token, ','); ret.push_back(token));
  return ret;
}

std::string serialize_array(std::string* array_ptr, std::size_t N)
{
  std::ostringstream cat;
  for(std::size_t index= 0; index< N; ++ index)
    cat<< array_ptr[index]<< ',';
  std::string ret= cat.str();
  return ret.substr(0, ret.size()-1);
}

int main()
{
  std::string data= "1,2,3";
  std::cout<< "Data: "<< data<< std::endl;
  std::vector<std::string> deserialized= deserialize_array(data);
  std::string serialized= serialize_array(deserialized.data(), deserialized.size());
  std::cout<< "Serialized + Deserialized: "<< serialized<< std::endl;
}

Instead of spending time parsing parentheses and extra commas, you can serialize as csv and read two by two when processing the deserialized data.

nurettin
  • 11,090
  • 5
  • 65
  • 85
1

This is what I envision, though it may be incorrect:

<table>
  <citation>
    <citation ID>
    <citation content>
    <citation publication date>

CREATE TABLE citation
(
    citation_ID INTEGER PRIMARY KEY AUTOINCREMENT,
    citation VARCHAR(255)
    published datetime
    )


<table>
  <source doc>
    <source doc ID>
    <source doc content>

CREATE TABLE source
(
    source_ID INTEGER PRIMARY KEY AUTOINCREMENT,
    source VARCHAR(5000)
    )

<citation_to_source table> //table in question
  <relationship>
    <relationship ID>
    <citation ID>
    <source doc ID>

CREATE TABLE citation_to_source //table in question
(
    relationship_id INTEGER,
    citation_ID INTEGER,
            source_ID INTEGER,
            FOREIGN KEY(citation_ID) REFERENCES citation(citation_ID)
            FOREIGN KEY(source_ID) REFERENCES source(source_ID)
    )

Output format:

<content>
  <relationship ID>
  <unique source document content>
  <enumerate citation IDs>
Wolfpack'08
  • 3,982
  • 11
  • 46
  • 78
0

I was dealing with the same issue. I came from JS but I think it'd be a cross-language answer. Since nobody gives a code example of the Gianni idea and Wolfpack'08 was asking for an example I'll leave my solution.

SELECT A.artistid, B.name, group_concat(A.title, '   --   ') titlesList 
FROM albums A
INNER JOIN artists B
ON A.artistid = B.artistid
GROUP BY A.artistid
LIMIT 10
;
Jony
  • 51
  • 9