views:

300

answers:

1

Hello! I want to make a relational database system for a local computer hardware non-profit. There are two inter-related features that I want to figure out how to implement. First, we need to manage our inventory of parts, and second, we need to track donations of computer systems as they come into us, and also as we grant them out.

First, we have a simple inventory of parts. We don't need to track individual parts ( we couldn't, anyway ), so what I want to model is the the count. My thought is to have different 'bins' of parts, that have just a simple count. So if we move a video card from its 'inventory' bin to the 'recycle' bin, I want a -1 to video-card-inventory, and +1 to video-card-recycling. Bins may be more well-defined as needed, such as pci-video-cards, agp-video-cards, etc. Or, if we count our inventory, we might need to do a -3 from inventory, and +3 to 'shrinkage'.

The point of that is to know at any time how many, say, video cards we have, how many sticks of ram, etc. The two aspects of a bin would be what kind of part is in it ( at whatever level of specificity, such as 'old-misc-card' or '32MB-3.3v-agp-video' ), and the purpose of the bin, such as 'donation-in', 'inventory', 'recycling', 'store', 'shrinkage', etc.

Also, we would like to see a trending of ebb and flow of parts, and historical data, so we need to do queries of inventory at any time.

So how would I design table(s) to handle that? I'm thinking it would be something like a double-entry ledger. I might have one table called 'BinTransactions' where there would be from_bin, to_bin, and amount. The amount would be a positive integer, and if I want to write a query see how much would be taken out of an inventory, I would make it negative. Something like "SELECT SUM(amount) * -1 FROM BinTransactions WHERE from_bin = 'inventory' AND time_period = ..."?

The second part of this is the computer systems themselves. They come in as donations in whatever state they're in. Parts may be taken out from them and put into inventory or recycling; parts may be taken out from inventory and put into computers. I guess I could make a computer a

A computer finally makes its way out of our system as a grant, but that structure sort of has one level of nesting. It's a collection of computer parts in the computer, but there is also monitor, keyboard, mouse, perhaps speakers. And a large grant may be several systems, also with networking equipment. Should 'nest' the logical hierarchy of groupings ( parts into computers, computers into grants ) , or would it be okay to just have every donation just one big group of parts? If it were one big group of parts, wouldn't necessarily know which parts went with which computer if we got a single computer back from a grant. Also we would like to be able to know from reports "34 complete systems were donated this quarter..."

A: 

This sounds like a problem that has already been solved: http://sourceforge.net/projects/phpmyinventory/ http://sourceforge.net/projects/asset-tracker/ These are just two links I found on sourceforge by typing 'inventory' in the search box.

The most basic description is this:

  • Computer parts come in.
  • Computer parts get stored.
  • Computer parts leave.

I am not strong enough with SQL to recommend a way to handle computer donations / sales and their breakdowns into parts - I would probably let some outside application handle most of that logic, and keep track of this:

  • Who donated a computer
  • To whom was a computer given

As far as logic handling: for instance, a webpage that says: "Woo! We received a computer! Does it have:

  1. A power supply?
  2. A video card?
  3. A sound card?
  4. And so on, and so forth."

The same can be done when giving a computer away - but you need to remove '1' from storage for each of the parts that goes away!

So, how do we handle the inventory? Well, you could have one table that looked like this:

video card   | recycle | donation-in | storage | garbage
sound card   | recycle | donation-in | storage | garbage
power supply | recycle | donation-in | storage | garbage

With each bin being how many there are at a point in time. If you want to make it more specific, you can add a "description" column, so you know how many of each type of video card you have, for instance.

And a table that looked like this:

part name | from_bin | to_bin | quantity

Most of the logic for moving the quantities around should probably be handled by the application (I am more of a Ruby-on-Rails guys, so this makes sense to me). Hope that helps.

Trevoke
I was hoping to find a solution where a computer was a set of parts, more like a bin. It will have transactions, like a bin, where parts go in and out.
The reason I want to stay away form 'hard-coding' part statuses in columns is because a computer that we get might be totally broken into parts and recycled. The entities I want to track in this model are the movements of parts -- the transactions between bins and computers -- not systems themselves.
Likewise, a system may come into existence by being assembled completely from parts. So the model I'm wanting to make is a system as a conflux of parts, not as an entity itself.
Add one more table: id | part_name Then you can have : 1 | video card 2 | sound card 3 | power supply 4 | keyboard 5 | mouse And you can just add rows to every other table by linking to those names - now the names aren't hard coded. As far as hard-coding the statuses, same thing. Make a table of statuses, and then link to those.That way you can end up with a table that does this:date | part_id | from_id | to_id 2010-01-20 14:15:14 | 5 | 1 | 4
Trevoke
You want "many parts" to become "one computer" -- and I don't know if you want that computer stored in the database as an addition or just shipped out.I'm not sure a database can do this for you, but with front-end logic, a database can be told "Okay, now we're removing one of each of those items, and adding one of this item".A database holds data and relationships between data. It doesn't hold business logic :)
Trevoke
Well, okay, but in this project, the main goal is to keep track of the flow of parts. If the final resting point of a part is in a system instead of a bin, and the database can't model the granting out of a system, that's fine. What we want to track in house is our inventory, which comes from part flows.
Let me follow your train of thought. Let me know if I'm wrong.You want to track which parts go from where to where. In order to do that, we need to know a part, an origin and a destination, a quantity, and maybe a timestamp.A part is... A part. You can put it in a table with an id and a description.An origin and a destination are locations: out, in, recycle, fridge. Those can be put in one table with an id and a description.The quantity, well, depends on the transaction. That has to stay in this table.The timestamp just gets tacked on to it.(continues)
Trevoke
Now, I just described exactly the system I suggested to you, minus the original table which says "we have this many of that part in yonder location". Presumably because doing the original inventory would be a pain and you want to avoid that.If all you -really- care about is the flow of parts through your location, then you don't need that last table.As a warning though, running reports might be really painful.Is that pretty much your thoughts?
Trevoke
Well, we don't really want to track parts individually. The system I was envisioning was more like a double-entry accounting system. In that database structure, I have a transactions table, whch says my checking account is -500, and my credit card account is +500, and the respective balances at a point in time are x and y. I don't really need to track each individual dollar that went from one account to the other -- I just care *how much*.
Similarly, in our shop right now, we don't track parts. All we have are inventory counts ( "We have 50 hard drives" "We pulled 10 sticks from RAM from computers" ). In this way, parts of the same type are fungible, like dollars. All we want to track in this inventory system is transactions, the amounts to and from, and use that to build balance queries, such as "You have 50 hard drives right now" or "Inventory of hard drives have been trending downward since June". Just like currency accounting.
Even if we wanted to track parts, we couldn't organizationally ( who's going to type part serial numbers into the database? We can't afford thermally-printed serial number stickers -- this is a charity ), nor does it really gain us anything. Who cares that RAM stick #283985209348 was pulled from a computer and put in a bin? We just threw one in the bin after it passed testing. +1 to inventory, -1 from testing.
Ah! I see. What I have been describing to you does not track single parts, only amounts. I still believe that it is the simplest way to track all the data you want to track.I would add a simple SQL job to regularly do an inventory query and store that in another table with the date and the bins, so you can see, over time, the changes in balance in each bin.I think the misunderstanding stems from what we think 'inventory' means. I just mean "keeping track of what we have".I tell you what - this will be a good exercise for me, I'll build you something simple to show what I mean.
Trevoke
:) OK -- what database? If it's not postgres or mysql, I won't be able to run it.
MySQL.. It's what I have installed. It'll also be Ruby on Rails.It'll take me a little while to do, since I have other obligations - so if you have more questions, about exactly what I am suggesting and how it differs from what you want, by all means, ask!I am really hoping I get your firstborn child, or at least a green mark, when this is all set :p
Trevoke
hm... I don't have a RoR environment! Is this just the table structure and queries you're writing?
Sure. I'll just give you the database skeleton/template, then.
Trevoke
Here it is : http://gist.github.com/283897 What is missing is a stored procedure / scheduled task to do a regular poll of the bins and add the total to the table 'monthly counts' - for easier reporting purposes of the changes in quantity over time. Let me know how that goes for you.
Trevoke
Does that link help you at all? Anything amiss?
Trevoke
Sorry it took me a while to respond, I got busy with other things. In our warehouse, I don't think we'll be able to track parts by type individually. Anything residing in the same box is the same 'part' -- such as 'useable hard drives' or 'hard drives for testing'. So I would get rid of the parts table. There are just things moving from bin to bin, and what they are depends solely on which bin they reside in. Also, I was trying to think of how computer systems cold be like bins, which also accept part flows. If you post the code to another answer, I'll upvote and accept it.
A "hard drive" is a part. Why would you get rid of that, since it's precisely what you're trying to track? "Usable" would be a bin. "To_test" would be another bin.Here... Read this: http://rdbms.ca/database/introduction.htmlMaybe it'll help you understand better.
Trevoke
We're not necessarily trying to track that. We just trying to count how many things we have where. The parts table is over-engineering. If we move 12 sticks of RAM and 20 old modem cards into 'recycling', we don't care how many ram sticks we have in there, nor how many modems. All we care about is 32 things went from two bins into one.
Or, your could say in other words, parts get their identity from where they're located; it's not inherent. Or, even another way to think of it is, we really aren't tracking parts. We just want to track the counts of bins at various times.
Let's try a contrived example, then.You have:A "just received" bin with 15 sticks of RAM and 4 mice. It has 19 items.A "tested-good" bin with 3 keyboards and 6 hard drives. It has 9 items.A "tested-bad" bin with 4 power supplies and 2 AAA batteries. It has 6 items.All you want to know is that 4 items went from "just received" to "tested-good" -- and it doesn't matter to you whether the 4 mice went, or one mouse and three sticks of RAM. Is that right?
Trevoke
Well, they would go into `tested-good-mice-trackball`, `tested-good-mice-optical`, `tested-good-512MB-DDR2`, etc. I mean, those are the boxes we literally have right now. So I'm trying to have a data model that conforms to what we're already using. Otherwise, that makes acceptance very difficult. And I'm not sure that we could even handle a more fine-grained system, organizationally. All parts within their container are fungible. If they are different, they go into another box.
How exactly is that different from the system I've given you? You have parts and bins. That means that if an OPTICAL_MOUSE has part_id 1, and if TESTED-GOOD bin is bin_id 1, then you can have 15 of part 1 in bin 1. And that's 15 good optical mice... In the good optical mice bin.If TESTED-BAD is bin_id 2, then if you have 5 of part 1 in bin 2, then you have 5 bad optical mice.You are welcome to add an "unidentified" part, and only have 587 unidentified objects in your inbox - and then, decrease unidentified in inbox and increase something else somewhere else.Does this still not make sense?
Trevoke
I'm mulling over how it may be different, but in the meantime, this question that occurs to me: if it's not different, why bother? If it's functionally the same, but structurally simpler, shouldn't I go with the simpler data model? The schema with `parts` is more complicated -- it has an extra table. If we can get rid of it, why not? It would make querying simpler.
Because with the added table, you get much more flexibility, and less data repetition, which means a smaller database.
Trevoke
Can you give me some scenarios that exemplify the additional flexibility, and the lack of repetition?
*sigh* You don't really have any kind of database experience, do you? If you only have a bin table, then you need a row for "video-cards-good", a row for "video-cards-bad", a row for "video-cards-to-test", and then just one column for each count. And every time you have a new part, you have to add X rows, where X is the number of bins.If you have a bin table and a parts table, then you can have a single row for video cards, a column for each bin, and the count in the appropriate cell. Just add a row for a new part, a column for a new bin - and EVERYTHING gets the new bin.
Trevoke