store unknown size array in mysql database - php

Hi I have in mysql database a datetime value (2015-01-01 12-54-32) which I use to know the date in which the library subscriber reserved a book it is easy to store one datetime value in database but the problem is i don't know how many books the subscriber will reserve from the library could be 1 or could be 5 , the question is how do i store it in database as array ?

The correct way to store this in a database is to use a junction table. Something like this:
create table BookReservations (
BookReservationId int auto_increment primary key,
SubscriberId int not null,
BookId int not null,
ReservationDate date not null,
constraint fk_bookreservations_subscriberid foreign key (SubscriberId) references Subscribers(SubscriberId),
constraint fk_bookreservations_bookid foreign key (BookId) references Books(BookId)
);
(Clearly, this just suggests names for entities and columns not mentioned in the question.)
Note that this table defines the foreign key relationships among the tables as well as storing the data. This allows the database to ensure relational integrity. MySQL does not (currently) allow such definitions for string or JSON objects.

If you really want to store multiple books in one field you can json_encode the array everytime you store it and then json_decode it again when you select it from the db.
But the better approach is to create a book_subscribe table where you can store as many as you like per subscriber.

Use serialize and unserialize to covert arrays and add it in your database column. Your question makes me think you have a database design issue. Take a look at one-to-many relationships (eg. one customer, several books)

Related

Doctrine with one field of the composite primary key to be auto generated

I currently have a table that has as primary key a composite value formed by id + foreign key. The id is auto-incremented and the foreign key references another table.
At the moment that I'm saving the data I only know about the foreign key value and I expect that the id returns to me from the database as an auto-increment number.
I understand that doctrine's does not support auto generation of id for a composite primary key so what can be done to allow with Doctrine to save the data and still have the auto-increment on part of the composite key.
Note, before submiting this question I had researched several other questions such as: Defining Composite Key with Auto Increment in MySQL and Doctrine: authorize NULL in a foreign composite key and I have also read Doctrine's documentation several times to see if I was missing something http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes
The main issue is that on Doctrine
Every entity with a composite key cannot use an id generator other than
“ASSIGNED”. That means the ID fields have to have their values set before
you call EntityManager#persist($entity).
To help with the issue here is an example of how the table is constructed:
create table composite_example (
id int(11) not null auto_increment,
fk_id int(11) not null,
a_prop varchar(20),
primary key (id, fk_id)
) engine=InnoDB default charset=utf8;
If I had to manually construct a MySQL query to insert into this table knowing the values of fk_id and a_prop I could do:
insert into composite_example (fk_id, a_prop) values (999, 'a_value');
And it would create a row with a proper value for id on the table.
How can I do the same behavior with Doctrine ? Does anyone knows any way or workaround to get the job done ?
There is no easy solution for this matter but here are a few options:
1) You can remove composite key and use UUIDs as keys. This is not an easy solution because it will affect how much of your code needs to be changed, how long it will take to do the migration and how it can affect performance.
2) The other option would be something that was suggested by the Doctrine community that can be used in other ORM's as well: you work with a sequencer. For this solution you will need to create a table where you will store an entity identifier and the next column will be the last value for that identifier.
Example:
Table sequencer
id | entity_name | entity_id
88 | customers | 77
The entity model would need to inform that the id is generated and on the pre-persist it will need to assign that id with a value that would come from the entity_id + 1 out of this table
select max(entity_id)+1 from sequencer where entity_name = 'customers';
This will cause 2 extra queries to be ran, one on the pre-persist and another on the post-persist which will update the sequencer table with the new value.
There are strategies to avoid concurrency on the sequencer table so it would always have the correct value and one of them is by locking the table o.0
3) You can write your own loaders and persister, but at this point you might be facing a change as big as the UUID implementation.
A lot of ORM's doesn't support this and if you are facing the same issue, you might have to consider one of the above.
Now, if you are working specifically with Doctrine I strongly suggest asking for help on the IRC channel. They were very helpful on providing me with some alternatives for this issue.

How Do I get RedBeanPHP to work with a MySQL Table with ID primary key (uppercase only)? [duplicate]

If you use RedBean ORM, do you need to add a primary key named "id" to every table in your database?
In my db I have a few tables that have primary keys pairs of 2 or 3 fields, or primary keys with other names than "id" (yes, I could change the name to "id", but it wouldn't really reflect the reality, because they are not IDs)
Example:
table1 - stores posts:
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
title TEXT,
content TEXT,
table2 - stores meta for posts:
post INTEGER DEFAULT 0, # <- references "id" from "posts"
name TEXT,
value TEXT,
PRIMARY KEY(name, post),
CONSTRAINT posts_meta FOREIGN KEY(post)
REFERENCES posts(id) ON DELETE CASCADE ON UPDATE RESTRICT
Would RedBean work with this kind of db structure?
Unfortunately, with how your current table structure is, you couldn't use RedBean. Every table needs to have an auto-increment primary key. A slight downfall, as it makes integration into an already existing product more difficult.
A couple of threads that failed to use RedBean due to this constraint, with responses from the author, Gabor De Mooij:
http://groups.google.com/group/redbeanorm/browse_thread/thread/6d5582275326744f?pli=1
http://groups.google.com/group/redbeanorm/browse_thread/thread/4fa7b29b453dcdb8
RedBean does NOT require the primary key field to be named simply "id", however. You can format the name of the primary key column to your liking by using the formatBeanID() method, as seen in the example below, which prefixes the table name to the "id" conditionally. eg) table users would have the primary key be users_id. Using that formatting, you can get as detailed with the id name as needed.
http://redbeanphp.com/community/wiki/index.php/Prefixes
Hopefully this restraint will be lifted in the future, since it really does hamper the integration into existing products.
EDIT: As an alternative ORM, I've heard well of Doctrine: http://www.doctrine-project.org/. I haven't personally used it, but it seems to be the standard for many working with PHP.
EDIT 2: Thanks and credit to Jason for bringing to attention a new method for integrating RedBean into an existing project where your database might not be set up for it. I wanted to update my answer as well in case people still reference it with this problem. Gabor suggested making views that map to the tables, where you can set up the view to have the proper structure required for RedBean. I have not personally tested this, but it has gotten positive feedback from some users. It adds some extra overhead and maintenance when altering tables, but seems to be the best and most complete answer to this issue to date.
http://www.redbeanphp.com/faq#beanformatter
The accepted answer is not strictly true... You can use the existing table structure - but you would need to implement a VIEW on top of each of the tables that allow you to rename the PKEY column to be 'id'... See this email from Gabor - the creator of RedBeanPHP:
https://groups.google.com/forum/#!searchin/redbeanorm/view/redbeanorm/wXUeT4Tj2uU/3AngnmVwZdYJ

Merge several mySQL databases with equivalent structure

I would like write a php script that merges several databases, and I would like to be sure of how to go around it before I start anything.
I have 4 databases which have the same structure and almost same data. I want to merge them without any duplicate entry while preserving (or re-linking) the foreign keys.
For example there is a db1.product table which is almost the same as db2.products so I think I would have to use LIKE comparison on name and description columns to be sure that I only insert new rows. But then, when merging the orders table I have to make sure that the productID still indicates the right product.
So I thought of 2 solutions :
Either I use for each table insert into db1.x as select * from db2.x and then make new links and check for duplicate using triggers.
Either I delete duplicate entries and update new foreign keys (after having dropped constraints) and then insert row into the main database.
Just heard of MySQL Data Compare and Toad for mySQL, could they help me to merge tables ?
Could someone indicate to me what should be the right solution ?
sorry for my english and thank you !
First thing is how are you determining whether products are the same? You mentioned LIKE comparison on name and description. You need to establish a rule what says that product is one and the same in your db1, db2 and so on.
However, let's assume that product's name and description are the attributes that define it.
ALTER TABLE products ADD UNIQUE('name', 'description');
Run this on all of your databases.
After you've done that, select one of the databases you wish to import into and run the following query:
INSERT IGNORE INTO db1.products SELECT * FROM db2.products;
Repeat for the remaining databases.
Naturally, this all fails if you can't determine how you're going to compare the products.
Note: never use reserved words for your column names such as word "name".
Firstly, good luck with this - sounds like a tricky job.
Secondly, I wouldn't do this with PHP - I'd write SQL to do the work, assuming this is a one-off migration task and not a recurring task.
As an approach, I would do the following.
Create a database with the schema you want - it sounds like each of your 4 databases have small variations in the schema. Just create the schema for now, don't worry about the data.
Create a "working" database, with the same schema, but with columns for "old" primary keys. For instance:
table ORDER
order_id int primary key auto increment
old_order_id int not null
...other columns...
table ORDER_LINE
order_line_id int primary key auto increment
old_order_line_id int not null
order_id int foreign key
...other columns...
Table by table, Insert into your working database from your first source database. Let the primary keys auto_increment, but put the original primary key into the "old_" column.
For instance:
insert into workingdb.orders
select null, order_id, ....other columns...
from db1.orders
Where you have a foreign key, populate it by finding the record in the old_ column.
For instance:
insert into workingdb.order_line
select null, ol.order_line_id, o.order_id
from db1.order_line ol,
workingdb.order
where ol.order_id = o.old_order_id
Rinse and repeat for the other databases.
Finally, copy the data from your working database into the "proper" database. This is optional - it may help to retain the old IDs for lookups etc.

Why in mysql store data like this a:6:{s:5:"title";s:43:}

In mysql database , I find some data store like below:
a:6:{s:5:"title";s:43:"fgjfh";s:8:"province";s:6:"重庆";s:4:"city";s:9:"大渡口";s:8:"location";s:6:"fhfghf";s:9:"starttime";s:11:"09-02
12:00";s:7:"endtime";s:11:"09-02 16:00";}
That's a PHP serialized array. You serialized your array before putting it to the database.
Look for serialize($value) calls in your code if you want to change it.
Update:
Probably your stored data (which is a hash actually) has dynamic fields, and it was too difficult for the creator or he/she didn't care/was lazy to do so/decided that's not important or simply that was not the use case.
But you should consider to rethink your schema and create a correct (3NF) normalization. In this case you will have at least one table which can be like this:
CREATE TABLE data (
id INTEGER PRIMARY KEY, -- or SERIAL if your database supports it
title VARCHAR, -- or TEXT
province_id INTEGER NOT NULL, -- or REFERENCES the provinces table
city_id INTEGER NOT NULL, -- or REFERENCES the cities table
location VARCHAR, -- I do not really know what is this field
starttime TIMESTAMP,
endtime TIMESTAMP
);
And of course your you'll need the provinces and the cities tables as well. With this schema you could use database instructions to work with the stored data if you need so.

retrieve a multi-column PK in MySQL

How do I retrieve a multi-column PK in MySQL?
For example I have my primary key setup as
PRIMARY KEY (donor_id,country_id)
Now if I want to get the primary key value without concatenating those 2 fields in a select query, how do I do that? I want to use this in a view (or better yet, directly in phpmaker).
It's not clear what you mean by "without concatenating". A simple
SELECT donor_id, country_id FROM table WHERE ...;
will retrieve the records; you don't need to apply a CONCATENATE() function or anything like that. This is the Right Way to select two records from a table; the fact that they both happen to be declared part of the primary key changes nothing.
No special way is needed to get the records from table that has a multi-column PK in MySQL. Things might be different if you are using an ORM. An ORM may or may have special or different syntax/features for working with tables with multi-column PK.

Categories