Is this possible to join tables in doctrine ORM without using relations? - mysql

Suppose there are two tables.
Table X--
Columns:
id x_value
Table Y--
Columns:
id x_id y_value
Now I dont want to define relationship in doctrine classes and i want to retrieve some records using these two tables using a query like this:
Select x_value from x, y where y.id="variable_z" and x.id=y.x_id;
I m not able to figure out how to write query like this in doctrine orm
EDIT:
Table structures:
Table 1:
CREATE TABLE IF NOT EXISTS `image` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`random_name` varchar(255) NOT NULL,
`user_id` int(11) NOT NULL,
`community_id` int(11) NOT NULL,
`published` varchar(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=259 ;
Table 2:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`city` varchar(20) DEFAULT NULL,
`state` varchar(20) DEFAULT NULL,
`school` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=20 ;
Query I am using:
$q = new Doctrine_RawSql();
$q ->select('{u.*}, {img.*}')
->from('users u LEFT JOIN image img ON u.id = img.user_id')
->addComponent('u', 'Users u')
->addComponent('img', 'u.Image img')
->where("img.community_id='$community_id' AND img.published='y' AND u.state='$state' AND u.city='$city
->orderBy('img.id DESC')
->limit($count+12)
->execute();
Error I am getting:
Fatal error: Uncaught exception 'Doctrine_Exception' with message 'Couldn't find class
u' in C:\xampp\htdocs\fanyer\doctrine\lib\Doctrine\Table.php:290 Stack trace: #0
C:\xampp\htdocs\fanyer\doctrine\lib\Doctrine\Table.php(240): Doctrine_Table- >initDefinition() #1 C:\xampp\htdocs\fanyer\doctrine\lib\Doctrine\Connection.php(1127):
Doctrine_Table->__construct('u', Object(Doctrine_Connection_Mysql), true) #2
C:\xampp\htdocs\fanyer\doctrine\lib\Doctrine\RawSql.php(425): Doctrine_Connection-
>getTable('u') #3 C:\xampp\htdocs\fanyer\doctrine\models\Image.php(33): Doctrine_RawSql-
>addComponent('img', 'u.Image imga') #4 C:\xampp\htdocs\fanyer\community_images.php(31):
Image->get_community_images_gallery_filter(4, 0, 'AL', 'ALBERTVILLE') #5 {main} thrown in
C:\xampp\htdocs\fanyer\doctrine\lib\Doctrine\Table.php on line 290

Try something like this:---
$q = new Doctrine_RawSql();
$this->related_objects = $q->
select('{o.name}')->
from('tagset t1 JOIN tagset t2 ON t1.tag_id = t2.tag_id AND t1.object_id != t2.object_id JOIN object o ON t2.object_id = o.id')->
addComponent('o','Object o')->
where('t1.object_id = ?', $this->object->id)->
groupBy('t2.object_id')->
orderBy('COUNT(*) DESC')->
execute();

You can write the sql directly to the db driver.You won't get back any hydrated arrays or objects however. But it does come in handy sometimes:
$sql = "SELECT * FROM... ";
$pdo = Doctrine_Manager::connection()->getDbh();
$data = $pdo->query($sql)->fetchAll();

You can manually alter your Table Class in Symfony 1.4 but this should be done carefully, because you are not linking tables on Database level which normally should happen.
class TableName extends BaseTableName
{
public function setUp()
{
$this->hasOne('LinkedTableName', array(
'local' => 'link_id',
'foreign' => 'link_id'));
parent::setUp();
}
}
Possible duplicate: doctrine join without relation

Related

MYSQL - Select and parse

I have my databse: public
I have my table: info
in row files of player Maria i have this:
['python22.dll', ''], ['python27.dll', ''], ['channel.inf', ''], ['devil.dll', ''],['is_hack.exe', '']
The first 4 is normal so I don't want to see them in the list .. i just want to catch the "is_hack.exe"
My mysql query to get all ( including my normal files) is:
query("SELECT files FROM public.info WHERE player = 'Maria' ORDER BY actual_time DESC LIMIT 0,1;")
I need to see all the names that are not mine. Like:
FILE_FROM_OUTSIDE1 = is_hack.exe
FILE_FROM_OUTSIDE2 = stackoverflow.dll
If you know about LUA, i can get the entire query results to LUA then begin to parse.. but how?
EDIT:
This is my table:
CREATE TABLE `info` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`player` varchar(12) DEFAULT NULL,
`type_check` varchar(10) DEFAULT NULL,
`normal` varchar(20) DEFAULT NULL,
`actual` int(3) DEFAULT NULL,
`actual_time` varchar(20) DEFAULT NULL,
`files` varchar(3000) DEFAULT NULL,
PRIMARY KEY (`id`)
In "files" i have all this:
['python22.dll', ''], ['python27.dll', ''], ['channel.inf', ''], ['devil.dll', ''],['is_hack.exe', '']
I just want to select the is_hack.exe .. like: print is_hack.exe
I'm not sure if this is what you want. But i think this might help:
Replace the filename_field with your col name.
query("SELECT files FROM public.info WHERE player = 'Maria' AND filename_field = 'is_hack.exe' ORDER BY actual_time DESC LIMIT 0,1;")
UPDATE
I don't know if this I'm right but you should not save data like this. You can create a files table and specify which user own each row. Like:
CREATE TABLE `playerfiles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`player` int(11) DEFAULT NULL,
`filename` varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
);
Then you can retrieve data with JOIN.
SELECT * FROM `info`
JOIN `playerfiles` ON `playerfiles.player` = `info.id`
WHERE `info.player` = 'Maria' and `playerfiles.filename` = 'THE NAME'

Speed up the following queries by merging them into one

I need to find a way for merging two queries into one.
This is the structure of the tables I am using:
(there are also other fields on contents and ratings but I didn't add them, since they aren't needed for this.
-- Create syntax for TABLE 'contents'
CREATE TABLE `contents` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`rating` decimal(5,4) DEFAULT '0.0000',
`ratingsCount` int(8) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'ratings'
CREATE TABLE `ratings` (
`what` int(11) DEFAULT NULL,
`time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`rating` decimal(3,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Since last time I asked something here on stack overflow someone told me to write the code I'm using right now. Here it is:
db.query("SELECT AVG(rating) `avg`, COUNT(rating) cnt FROM `ratings` WHERE what = ?", [req.params.id], function(err, avg) {
db.query("UPDATE contents SET `rating` = ?, `ratingsCount` = ? WHERE id = ?", [avg[0].avg, avg[0].cnt, req.params.id], function() { });
});
You could use an UPDATE/JOIN combination to do it in a single round trip to the database;
UPDATE contents c
JOIN (
SELECT what, AVG(rating) rating, COUNT(rating) ratingsCount
FROM ratings WHERE what = ? GROUP BY what
) r
ON c.id = r.what
SET c.rating = r.rating, c.ratingsCount = r.ratingsCount
An SQLfiddle to test with.
The subquery will find the average/count for the value of "what", the outer query will just join that information to update contents.
This one will do the work:
UPDATE contents c SET
rating=(SELECT AVG(rating) FROM ratings r WHERE r.what=c.id),
ratingsCount=(SELECT COUNT(rating) FROM ratings r WHERE r.what=c.id);
You'll need to add index for id and what columns.

Mysql query optimisation to transform subquery in join without DISTINCT

I have tables:
CREATE TABLE IF NOT EXISTS `bk_cart_rule` (
`id_cart_rule` int(10) unsigned NOT NULL DEFAULT '0',
`cart_rule_restriction` tinyint(1) unsigned NOT NULL DEFAULT '0',
KEY `id_cart_rule` (`id_cart_rule`),
KEY `cart_rule_restriction` (`cart_rule_restriction`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `bk_cart_rule_combination` (
`id_cart_rule_1` int(10) unsigned NOT NULL,
`id_cart_rule_2` int(10) unsigned NOT NULL,
KEY `id_cart_rule_1` (`id_cart_rule_1`),
KEY `id_cart_rule_2` (`id_cart_rule_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `bk_cart_rule_lang` (
`id_cart_rule` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
KEY `id_cart_rule` (`id_cart_rule`),
KEY `id_lang` (`id_lang`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And a query :
SELECT SQL_NO_CACHE cr.*, crl.*, 1 as selected FROM bk_cart_rule cr
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2)
WHERE cr.id_cart_rule != 375 AND
( cr.cart_rule_restriction = 0 OR
cr.id_cart_rule IN (
SELECT IF(id_cart_rule_1 = 375, id_cart_rule_2, id_cart_rule_1) FROM bk_cart_rule_combination WHERE 375 = id_cart_rule_1 OR 375 = id_cart_rule_2 ) )
Obvious optimization is:
SELECT SQL_NO_CACHE DISTINCT cr.*, crl.* 1 as selected FROM bk_cart_rule cr
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2)
LEFT JOIN bk_cart_rule_combination crc ON (375 = crc.id_cart_rule_1 AND cr.id_cart_rule = crc.id_cart_rule_2) OR (375 = crc.id_cart_rule_2 AND cr.id_cart_rule = crc.id_cart_rule_1)
WHERE cr.id_cart_rule != 375 AND (cr.cart_rule_restriction = 0 OR NOT ISNULL(crc.id_cart_rule_1))
But how can i get rid off DISTINCT (in bk_cart_rule_combination I've two-way combinations : )
id_cart_rule_1 id_cart_rule_2
375 776
776 375
Or maybe there is a better optimization possible?
If the ordering of the cart rules is not important, then add the constraint that the id for the first one is less than the id of the second one. That is, put them in the table in order.
Sadly, MySQL doesn't allow simple check constraints. Instead, you have to implement it in some other way. Here are three:
Implement an insert/update trigger to maintain the ordering (and prevent duplicates).
Implement the logic on the application side.
Wrap all data modifications in stored procedures and implement the logic in the stored procedure.
If you don't want to go through all that trouble (which would probably help with other issues), you can replace the select distinct with:
group by least(id_cart_rule_1, id_cart_rule_2), greatest(id_cart_rule_1, id_cart_rule_2)

How to update the WHERE clause to select identical data?

CREATE TABLE `schedule` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`aircraftType` varchar(50) DEFAULT NULL,
//...other fields
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=5611 DEFAULT CHARSET=latin1;
CREATE TABLE `aircrafts` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`aircraftType` varchar(50) DEFAULT NULL,
//...other fields
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=5611 DEFAULT CHARSET=latin1;
SAMPLE CONTENT OF DB TABLES:
Table "Schedule"
aircraftType = "320"
Table "Aircrafts"
aircraftType = "A320"
aircraftType = "A330"
Query:
SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = A.aircraftType;
How to update this query in such a way that aircratf types "320" and "A320" would be considered as similar in the WHERE clause?
SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = A.aircraftType LIKE CONCAT('%', F.aircraftType, '%')
OR
LIKE CONCAT('\"','%', F.aircraftType, '%','\"')-added double quotes.
Try cutting of first char with SUBSTRING() :
SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = SUBSTRING(A.aircraftType, 2)
Or like #Mihai suggested, just put % on field that hasn't have A in it :
SELECT *
FROM Schedule F, Aircrafts A
WHERE CONCAT('%', F.aircraftType) LIKE A.aircraftType
But best solution would be to update data for identical relation string.

MySQL query killing my server

Looking at this query there's got to be something bogging it down that I'm not noticing. I ran it for 7 minutes and it only updated 2 rows.
//set product count for makes
$tru->query->run(array(
'name' => 'get-make-list',
'sql' => 'SELECT id, name FROM vehicle_make',
'connection' => 'core'
));
while($tempMake = $tru->query->getArray('get-make-list')) {
$tru->query->run(array(
'name' => 'update-product-count',
'sql' => 'UPDATE vehicle_make SET product_count = (
SELECT COUNT(product_id) FROM taxonomy_master WHERE v_id IN (
SELECT id FROM vehicle_catalog WHERE make_id = '.$tempMake['id'].'
)
) WHERE id = '.$tempMake['id'],
'connection' => 'core'
));
}
I'm sure this query can be optimized to perform better, but I can't think of how to do it.
vehicle_make = 45 rows
taxonomy_master = 11,223 rows
vehicle_catalog = 5,108 rows
All tables have appropriate indexes
UPDATE: I should note that this is a 1-time script so overhead isn't a big deal as long as it runs.
CREATE TABLE IF NOT EXISTS `vehicle_make` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`product_count` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=46 ;
CREATE TABLE IF NOT EXISTS `taxonomy_master` (
`product_id` int(10) NOT NULL,
`v_id` int(10) NOT NULL,
`vehicle_requirement` varchar(255) DEFAULT NULL,
`is_sellable` enum('True','False') DEFAULT 'True',
`programming_override` varchar(25) DEFAULT NULL,
PRIMARY KEY (`product_id`,`v_id`),
KEY `idx2` (`product_id`),
KEY `idx3` (`v_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `vehicle_catalog` (
`v_id` int(10) NOT NULL,
`id` int(11) NOT NULL,
`v_make` varchar(255) NOT NULL,
`make_id` int(11) NOT NULL,
`v_model` varchar(255) NOT NULL,
`model_id` int(11) NOT NULL,
`v_year` varchar(255) NOT NULL,
PRIMARY KEY (`v_id`,`v_make`,`v_model`,`v_year`),
UNIQUE KEY `idx` (`v_make`,`v_model`,`v_year`),
UNIQUE KEY `idx2` (`v_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Update: The successful query to get what I needed is here....
SELECT
m.id,COUNT(t.product_id) AS CountOf
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.id;
without the tables/columns this is my best guess from reverse engineering the given queries:
UPDATE m
SET product_count =COUNT(t.product_id)
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.name
The given code loops over each make, and then runs a query the counts for each. My answer just does them all in one query and should be a lot faster.
have an index for each of these:
vehicle_make.id cover on name
vehicle_catalog.id cover make_id
taxonomy_master.v_id
EDIT
give this a try:
CREATE TEMPORARY TABLE CountsOf (
id int(11) NOT NULL
, CountOf int(11) NOT NULL DEFAULT 0.00
);
INSERT INTO CountsOf
(id, CountOf )
SELECT
m.id,COUNT(t.product_id) AS CountOf
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.id;
UPDATE taxonomy_master,CountsOf
SET taxonomy_master.product_count=CountsOf.CountOf
WHERE taxonomy_master.id=CountsOf.id;
instead of using nested query ,
you can separated this query to 2 or 3 queries,
and in php insert the result of the inner query to the out query ,
its faster !
#haim-evgi Separating the queries will not increase the speed significantly, it will just shift the load from the DB server to the Web server and create overhead of moving data between the two servers.
I am not sure with the appropriate indexes you run such query 7 minutes. Could you please show the table structure of the tables involved in these queries.
Seems like you need the following indices:
INDEX BTREE('make_id') on vehicle_catalog
INDEX BTREE('v_id') on taxonomy_master