views:

289

answers:

2

I need an elegant way to store dynamic arrays (basically spreadsheets without all the functionality) of various sizes (both x and y), mostly being used as ENUMs, lists, lookup data, price sheets, that sort of thing. Multi-lingual would be a great bonus. Speed of the essence.

Here's an example of a typical "sheet" ;

            |  1 |  2 |   3 |   4
  -------------------------------
  model A   | 2$ | 5$ |  8$ | 10$
  model B   | 3$ | 6$ |  9$ | 12$
  model C   | 4$ | 8$ | 10$ | 13$

So, to get info, I would do ;

  $price = this_thing_im_after ( '3', 'model B' ) ;
  echo $price ;   // Prints '9$'

I'm in the PHP5 and Zend Framework world, but thoughts on design and SQL is just as dandy, even suggestions on and from the outside world, libs, extensions, etc. as I don't want to reinvent too much of the wheel. I need the backend stuff the most, and I'll write a GUI for dynamic sheets later. Thoughts, ideas, pointers?

Just an edit to point out that I'd prefer not to serialize and blob the data as I would like to query the indeces and sheets, perhaps even the data (or type for those who support such, now that would be awsome!) if I'm in a crazy mood. But again, this is not a breaker for me; if someone has a nice library or class for serializing in and out quickly out of a database with some simple querying, I'm all happy.

A: 

Is there any need to fetch only part of a spreadsheet, or query by contained data?

If you just want to store and retrieve the whole thing, I would just use an unambiguous textual representation of the array (e.g. serialize()) and store it as TEXT.

Tomalak
Well, I was hoping to escape serializing hell, and if I was really, really lucky, have indeces over the data so I can typify the sheet keys. But yes, I could simply serialize them all, and do away with the whole notion of having them in a database for easy storing. :) I have thought about it, though.
AlexanderJohannesen
Tomalak
Yeah, I don't want cell level granularity, but I'd love to have key / header / column name granularity. I'd also love to have each sheet to have multiple types, and just ask for all sheets of type 'product-price', for example. Hmm, a dynamic field in a serialize mush would accomplish that, I guess.
AlexanderJohannesen
What does "header / column name granularity" mean? Being able to fetch a row or column by it's name, or rather just cecking if it is there, and then fetch the whole sheet? Nothing speaks against storing the sheet type or other meta data in extra columns.
Tomalak
If you don't want cell granularity and you don't want a blob what do you want to store?
jmucchiello
Isn't it obvious? Somewhere in the middle. :) I like to query for keys, for example, or column headers. I'd *really* like to have typification as well, but hey, I'm dreaming, I know.
AlexanderJohannesen
+1  A: 

Other than serializing the whole thing into a blob field, you probably end up with a key/value table where your key is the row and col fields:

  CREATE TABLE sheet (
      sheet_id int not null,
      name varchar(32),
      rows int, -- stores max dimension if needed
      cols int, -- stores max dimension if needed
      primary key (sheet_id)
  );
  CREATE TABLE cells (
      cell_id identity, -- auto inc field for ease of updates
      sheet_id int not null, -- foreign key to sheet table
      row int not null,
      col int not null,
      value smalltext, -- or a big varchar depending on need
      primary key (cell_id), -- for updates
      unique index (sheet_id, row, col), -- for lookup
      index (value) -- for search
  );

  CREATE TABLE row_labels (
      sheet_id int not null,
      row int not null,
      label varchar(32),
      primary key (sheet_id, row)
  );

  CREATE TABLE col_labels (
      sheet_id int not null,
      col int not null,
      label varchar(32),
      primary key (sheet_id, col)
  );

This allows you to slice the data nicely:

 // Slice [4:20][3:5]
 SELECT row, col, value FROM cells
 WHERE sheet_id = :sheet
   AND row BETWEEN 4 AND 20
   AND col BETWEEN 3 AND 5
 ORDER BY row, col

 while ($A = fetch()) {
     $cell[$A['row'][$A['col']] = $A['value']; // or unserialize($A['value']);
 }
jmucchiello
Nice approach! Like such "solutions"!
Tom Schaefer