Im going to try my best to explain myself. Not 100% sure how to word this. I have data in multiple tables something like
tbl_rooms
tbl_tables
tbl_people_sitting_at_table
All these tables have there linking id's and what I want to do is build a "room" object and not query the db in the loops. Right now what i have is something like this
Pseudocode
foreach ($rooms as $room) {
$room->tables = get_all_the_table_by_room_id($room->room_id);
.....
foreach ($room->tables as $table) {
$table->people_sitting_at_table = get_all_the_people_by_table_id($table->table_id);
What I have work but I don't like the amount of queries required to build the object. Heres is an example what I am looking to send back
stdClass Object
(
[id] => 15
[room_name] => room_name
[tables] => Array
(
[0] => stdClass Object
(
[id] => 34
[table_name] => table_name
[people_sitting_at_table] => Array
(
[0] => stdClass Object
(
[id] => 45
[name] => name
What im having a hard time with is knowing how to organize all that if i was to get all the data up front.. If I get all the tables in the room and then all the people at all the tables how do i get the people nested under the right table efficiently
Not sure if this enough info to get my point across, if not let me know
Here is some SQL for the exaple
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE `tbl_people_sitting_at_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`table_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `tbl_people_sitting_at_table` (`id`, `name`, `table_id`) VALUES
(1, 'jim', 1),
(2, 'bob', 1);
CREATE TABLE `tbl_rooms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `tbl_rooms` (`id`, `name`) VALUES
(1, 'room one'),
(2, 'room two');
CREATE TABLE `tbl_tables` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`room_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `tbl_tables` (`id`, `name`, `room_id`) VALUES
(1, 'table one', 1),
(2, 'table two', 1);
I think you are looking for something called the model-mapper design pattern.
Your model is a simple class that stores the columns in the database. You create one model instance per row. The mapper does your actual sql queries, then loads each row into a new model instance. So for instance, you would have a Room model and a Room Mapper. Then you have a PersonRoom model and a PersonRoom mapper. The PersonRoom mapper would let you select all PersonRooms that have a given room ID.
One thing you can look at that does this for you is Doctrine. Alternatively, you can just write it yourself. I wrote a code generator so that I can just point the code generator at the table and it will write the model/mapper code for me. I can then just use the models and mappers.
Related
I need to insert null data if so come. I'm inserting data from EXCEL to my DB. The problem is that I made the table structure and field to allow nulls and also as a default to NULL.
The value is empty and pass all my logical validations but when inserted, left in 21:00:00
PHP :
if(!empty($r['tiempo_chip'])){
$resultados[$i]['tiempo_chip'] = $this->ExcelReader->timeFormat($r['tiempo_chip']);
}else{
$resultados[$i]['tiempo_chip'] = NULL;
}
Data :
[0] => Array
(
[numero] => 88
[tiempo_oficial] => 01:10:30
[tiempo_chip] =>
)
This is stored in the DB 21:00:00
CREATE TABLE IF NOT EXISTS `resultados` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`numero` int(11) NOT NULL,
`tiempo_oficial` time NOT NULL,
`tiempo_chip` time DEFAULT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=133 ;
I have this code on my controller:
$sql = "SELECT * FROM user WHERE id = " . $this->input->get('foo');
$foo = $this->db->query($sql);
echo '<pre>';
print_r($foo->result());
echo '</pre>';
die();
I've noticed that if I use this URL:
www.site.com?foo=1 OR 1 = 1
all data of the user table is shown:
Array
(
[0] => stdClass Object
(
[id] => 1
[email] => aaa#gmail.com
[password] => aaa
)
[1] => stdClass Object
(
[id] => 1
[email] => bbb#gmail.com
[password] => bbb
)
[2] => stdClass Object
(
[id] => 1
[email] => ccc#gmail.com
[password] => ccc
)
)
Is it possible to run another query that returns the data from the user_phone table?
Tables:
CREATE TABLE `user` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`email` VARCHAR(100) NOT NULL,
`password` VARCHAR(255) NOT NULL
PRIMARY KEY (`id`),
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
CREATE TABLE `user_phone` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_user` INT(11) UNSIGNED NOT NULL,
`number` INT(11) UNSIGNED NOT NULL
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
Data:
INSERT INTO `user`(`email`,`password`) VALUES ('aaa#gmail.com','aaa');
INSERT INTO `user`(`email`,`password`) VALUES ('bbb#gmail.com','bbb');
INSERT INTO `user`(`email`,`password`) VALUES ('ccc#gmail.com','ccc');
INSERT INTO `user_phone`(`id_user`,`number`) VALUES ('1','911911911');
INSERT INTO `user_phone`(`id_user`,`number`) VALUES ('1','922922922');
INSERT INTO `user_phone`(`id_user`,`number`) VALUES ('2','955955955');
INSERT INTO `user_phone`(`id_user`,`number`) VALUES ('3','711711711');
Thks
EDIT:
I'm aware of the existing mechanisms to prevent this from happening.
My question is if it's possible, and how, can I get data from other tables.
I think it's going to be like this.
www.site.com?foo=1 OR 1 = 1 union select * from user_phone where user_phone.id_user = user.id
CI comes with functions to escape variables for exactly this reason.
$foo = $this->input->get('foo');
$foo = $this->db->escape($foo);
$sql = "SELECT * FROM user WHERE id = {$foo}";
$foo = $this->db->query($sql);
echo '<pre>';
print_r($foo->result());
echo '</pre>';
die();
You should be able to bind your query using something like this:
$sql = "SELECT * FROM user WHERE id = ? AND name = ?";
$foo = $this->db->query($sql, array('foo', 'bar'));
As for getting data from other tables, you'd just need to construct a more elaborate sql query
You asked about querying data from 2 tables, to query 2 related tables you can use join. In your example user and user_phone are related. You perform sql queries with join like demo below. The user primary_key is the glue in user_phone table.
1 - select *
2 - pass the id we want to retrieve
3 - from which table
4 - perform a join or multiple joins
5 - get the result
try this
$this -> db -> select('*');
$this -> db -> where('id' => '1');
$this -> db -> from('user');
$this -> db -> join('user_phone', 'user_phone.id_user = user.id');
$query = $this -> db -> get();
How do I import this database correctly?
https://github.com/samanz/cakecart
Every time I import then I get this error:
Error
SQL query:
CREATE TABLE `categories` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`name` VARCHAR( 50 ) NULL default NULL ,
`parent_id` INT( 11 ) UNSIGNED default '0',
`order` INT( 3 ) default '0',
`image` VARCHAR( 50 ) NULL default NULL ,
`ids` VARCHAR( 225 ) NULL default NULL ,
`url` VARCHAR( 255 ) NULL default NULL ,
PRIMARY KEY ( `id` ) ,
FOREIGN KEY ( `parent_id` ) REFERENCES categories( `id` ) ,
UNIQUE KEY `url` ( `url` )
);
MySQL said: Documentation
#1005 - Can't create table 'db.categories' (errno: 150)
Foreign key is error 150, but there's much more tables than this error.
Please try import first then answer.
THis one works:
CREATE TABLE `categories` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`name` VARCHAR( 50 ) NULL default NULL ,
`parent_id` INT( 11 ),
`order` INT( 3 ) default '0',
`image` VARCHAR( 50 ) NULL default NULL ,
`ids` VARCHAR( 225 ) NULL default NULL ,
`url` VARCHAR( 255 ) NULL default NULL ,
PRIMARY KEY ( `id` ) ,
FOREIGN KEY ( `parent_id` ) REFERENCES categories( `id` ) ,
UNIQUE KEY `url` ( `url` )
);
Edit: Actually you only need to remove unsigned to make it work. But I don't really know why you want it to be default 0. It should be default NULL which is the default default.. :)
I believe the type of parent_id must be the same as id.
The problem is that,You are trying to create table category.In this table you are using forign key but this forign key included table isnot created yet.
So first create the table contaning parent_id .After that try to create the category table
I'm think it's giving you and error because you're referencing an nonexistent, not yet created, table which is the table your trying to create itself.
why don't you create the table first then add the constraint(foreign key)?
but there's a possible error that you may run into whole doing this in the same table. what would happen if the newly added record doesn't have a parent assigned to it? default value is 0. will this give you an error because there's no record with id=0?
I suggest you normalize this by creating a relationship table for this.
CREATE TABLE CategoryGroups //or whatever name you find fits.
(
`Cat_id` int(11) NOT NULL,
`Parent_id` int(11),
FOREIGN KEY (`Parent_id`) REFERENCES categories(`id`),
FOREIGN KEY (`Cat_id`) REFERENCES categories(`id`)
)
Best practices would be to normalize all data and remove all many to many relationships between any two tables by creating relationship tables.
I have the following SQL Query:
SELECT
upd.*,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`
FROM
updates AS upd
LEFT JOIN
subscribers AS sub ON upd.uid=sub.suid
LEFT JOIN
users AS usr ON upd.uid=usr.uid
WHERE
upd.deleted='0' && (upd.uid='118697835834' || sub.uid='118697835834')
GROUP BY upd.id
ORDER BY upd.date DESC
LIMIT 0, 15
where i get all user(118697835834) updates, his profile picture from another table using left join and also all his subscription users updates so can i show them in his newsfeed.
However as the updates get more and more so the query takes more time to load... right now using Codeigniter's Profiler i can see that the query takes 1.3793...
Right now i have created around 18k dummy accounts and subscribed from to me and vice versa so i can test the execution time... the times that i get are tragic considering that i am in localhost...
I also have some indexes where i suppose need more in the users table(username and uid as unique), updates table(update_id as unique and uid as index)
I suppose i am doing something wrong to get so bad results...
EDIT:
Running EXPLAIN EXTENDED result:
Array
(
[0] => stdClass Object
(
[id] => 1
[select_type] => SIMPLE
[table] => upd
[type] => ALL
[possible_keys] => i2
[key] =>
[key_len] =>
[ref] =>
[rows] => 22
[filtered] => 100.00
[Extra] => Using where; Using temporary; Using filesort
)
[1] => stdClass Object
(
[id] => 1
[select_type] => SIMPLE
[table] => sub
[type] => ALL
[possible_keys] =>
[key] =>
[key_len] =>
[ref] =>
[rows] => 18244
[filtered] => 100.00
[Extra] => Using where
)
[2] => stdClass Object
(
[id] => 1
[select_type] => SIMPLE
[table] => usr
[type] => eq_ref
[possible_keys] => uid
[key] => uid
[key_len] => 8
[ref] => site.upd.uid
[rows] => 1
[filtered] => 100.00
[Extra] =>
)
)
EDIT2: SHOW CREATE of Tables
Users table:
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uid` bigint(20) NOT NULL,
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`email` text CHARACTER SET latin1 NOT NULL,
`password` text CHARACTER SET latin1 NOT NULL,
`profile_picture_full` text COLLATE utf8_unicode_ci NOT NULL,
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL,
`date_registered` datetime NOT NULL,
`activated` tinyint(1) NOT NULL,
`closed` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid` (`uid`),
UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=23521 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Subscribers table:
CREATE TABLE `subscribers` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`sid` bigint(20) NOT NULL,
`uid` bigint(20) NOT NULL,
`suid` bigint(20) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=18255 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Updates table:
CREATE TABLE `updates` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`update_id` bigint(19) NOT NULL,
`uid` bigint(20) NOT NULL,
`type` text COLLATE utf8_unicode_ci NOT NULL,
`update` text COLLATE utf8_unicode_ci NOT NULL,
`date` datetime NOT NULL,
`total_likes` int(11) NOT NULL,
`total_comments` int(11) NOT NULL,
`total_favorites` int(11) NOT NULL,
`category` bigint(20) NOT NULL,
`deleted` tinyint(1) NOT NULL,
`deleted_date` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `i1` (`update_id`),
KEY `i2` (`uid`),
KEY `deleted_index` (`deleted`)
) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Try this one (without the GROUP BY):
SELECT
upd.*,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`
FROM
updates AS upd
LEFT JOIN
users AS usr
ON upd.uid = usr.uid
WHERE
upd.deleted='0'
AND
( upd.uid='118697835834'
OR EXISTS
( SELECT *
FROM subscribers AS sub
WHERE upd.uid = sub.suid
AND sub.uid = '118697835834'
)
)
ORDER BY upd.date DESC
LIMIT 0, 15
At least the columns that are used in Joins should be indexed: updates.uid, users.uid and subscribers.suid.
I would also add an index on subscribers.uid.
Try:
SELECT
upd.*,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`
FROM
updates AS upd
LEFT JOIN
subscribers AS sub ON upd.uid=sub.suid
LEFT JOIN
users AS usr ON upd.uid=usr.uid
WHERE
upd.deleted=0 and upd.uid in (118697835834,118697835834)
GROUP BY upd.id
ORDER BY upd.date DESC
LIMIT 0, 15
Note that ' has been removed from numeric values and bitwise operators changed to conventional operators.
don't use joins, try this one:
select *,
(select username from users where uid = upd.uid) as username,
(select profile_picture from users where uid = upd.uid) as profile_picture,
from updates as upd
WHERE
upd.deleted='0' && upd.uid='118697835834'
(not tested!)
maybe you have to check if there exists a subscriber in the where-clause with another sub-select.
Another way would be to make a join on sub-selects and not on the whole table. This may increase your performance also.
Shouldn't take too long to run; do you have an index on 'deleted'? What is the 'GROUP BY id' doing? Should it be UID? Can it come out, if ID is in fact just an auto increment, unique ID? (which would be expensive as well as pointless)
I think you'll be best separating this query into a select on the user table and then union those results with the select on the subscribers table.
I want to merge the results of two tables in to one.
Please refer the following tables :
Data from microblog table as Row array
Array ( [ID] => 46 [userID] => 1 [userNAME] => user [blog_content] => HAI DEAR [page_name] => honda [page_ID] => 31 [post_time] => 2011-10-18 11:06:54 )
Data from Page_review table as Row array
Array ( [page_review_id] => 5 [page_id] => 31 [page_review_by_id] => 31 [page_review_by_username] => user [page_review_time] => 2011-10-18 11:43:34 [page_review_content] => hai )
Table Microblog MySQL query:
DROP TABLE IF EXISTS `featurezme_store`.`microblog`;
CREATE TABLE `featurezme_store`.`microblog` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`userID` int(10) unsigned NOT NULL,
`userNAME` varchar(45) NOT NULL,
`blog_content` text NOT NULL,
`page_name` varchar(45) NOT NULL,
`page_ID` int(10) unsigned NOT NULL,
`post_time` datetime NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=latin1;
Table page_review
DROP TABLE IF EXISTS `featurezme_store`.`page_review`;
CREATE TABLE `featurezme_store`.`page_review` (
`page_review_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`page_id` int(10) unsigned NOT NULL,
`page_review_by_id` int(10) unsigned NOT NULL,
`page_review_by_username` varchar(145) NOT NULL,
`page_review_time` datetime NOT NULL,
`page_review_content` varchar(555) NOT NULL,
PRIMARY KEY (`page_review_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
the table Microblog is used to store blog posts & page_review is used to store reviews about pages[Microblog's are in pages].
My requirement is i want to show Blogposts & page reviews sorted by Date [post_time in Microblog & page_review_time on page_review].
how can i do this ? please help me.
Okay I have updated my answear, you can use union as you wanted.
Just have the same number of fields and because the results are placed the one unde the other use fields that make sense to be the one under the other. This example will bring all blogs and reviews created by a specific user (if page_review_by_id actually refers to the user id) and related to a specific page.
(
SELECT
`microblog`.`userID`,
`microblog`.`blog_content` as `blog or review`,
`microblog`.`post_time`,
`microblog`.`page_id`
from `microblog`
where `microblog`.`page_id`='1' and `microblog`.`userID`='1'
)
union
(
SELECT
`page_review`.`page_review_by_id`,
`page_review`.`page_review_content`,
`page_review`.`page_review_time`,
`page_review`.`page_id`
from `page_review`
where `page_review`.`page_id`='1' and `page_review`.`page_review_by_id`='1'
)
======== Edit== Suggesting a schema with foreign keys ================
Because I don't see any foreign keys in your schema if I could suggest optionaly a schema that applies foreign keys I present one below.
These rules are supported by this schema:
Blogs belong to the site and not to the user so there is not on delete cascade applied.
Blogs are created by users and a foreign key is applied so when a user id is inserted the consistency is assured through the foreign key.
The same goes for the page, a foreign key is applid without on delte cascade.
The same goes for the reviews table
If a user or page is deleted no child row is deleted
/********Create ***** ***/
CREATE TABLE user (
user_id int unsigned NOT NULL AUTO_INCREMENT,
username varchar(16) NOT NULL,
userpassword BLOB,
PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE page (
page_id mediumint unsigned NOT NULL AUTO_INCREMENT,
title varchar(55) NOT NULL,
PRIMARY KEY (page_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE microblog (
blog_id int unsigned NOT NULL AUTO_INCREMENT,
blog_content text NOT NULL,
date_created datetime NOT NULL,
author_id int unsigned NOT NULL,
page_id mediumint unsigned NOT NULL,
PRIMARY KEY (blog_id),
CONSTRAINT blogfk1 FOREIGN KEY (author_id)
REFERENCES user (user_id),
/NO ON DELETE CASCADE/
CONSTRAINT blogfk2 FOREIGN KEY (page_id)
REFERENCES page (page_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE page_review (
review_id int unsigned NOT NULL AUTO_INCREMENT,
review_content varchar(555) NOT NULL,
date_created datetime NOT NULL,
author_id int unsigned NOT NULL,
page_id mediumint unsigned NOT NULL,
PRIMARY KEY (review_id),
CONSTRAINT reviewfk1 FOREIGN KEY (author_id)
REFERENCES user (user_id),
/NO ON DELETE CASCADE/
CONSTRAINT reviewfk2 FOREIGN KEY (page_id)
REFERENCES page (page_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/************** ******/
/** ***Insertions*** **/
INSERT INTO user ( username,userpassword)
VALUES ('username11', AES_ENCRYPT('password1',
'encription_key') ),
('username22', AES_ENCRYPT('password2',
'encription_key') );
INSERT INTO page ( title) VALUES
('title1'),('title2');
INSERT INTO microblog (blog_content,date_created,
author_id,page_id) VALUES
('blogcontent1','2011-2-2 12:00','1','1'),
('blogcontent2','2011-2-2 12:00','2','2');
INSERT INTO page_review (review_content,
date_created,author_id,page_id) VALUES
('reviewcontent1','2011-2-2 12:00','1','1'),
('reviewcontent2','2011-2-2 12:00','2','2');
/***** *******/
/******* Queries *** /
/Help on Identifing a user/
SELECT username
FROM user WHERE username ='username22'
and userpassword=AES_ENCRYPT('password2','encription_key')
(
SELECT
microblog.blog_content as blog or content,
microblog.date_created,
microblog.author_id,
microblog.page_id
from microblog
where microblog.author_id='1' and microblog.page_id='1'
)
union
(
SELECT
page_review.review_content,
page_review.date_created,
page_review.author_id,
page_review.page_id
from page_review
where page_review.author_id='1' and page_review.page_id='1'
)