Yii2 - Union of two queries - mysql

Good morning Everyone,
I need a little help. I have 2 SQL queries that i need to unite. This is my first query.. (sorry if this is gonna be long)
$query1 = new Query();
$query1->params([':category' => $category, ':ownerId' => $ownerId]);
$query1->select('tmp.id, tmp.title , tmp.description, asst.thumbAssetUrl, b1.paramVal as duration, b2.paramVal as clips, asst.fileUrl as video')
->from('listdb.baseData tmp')
->innerJoin(
'listdb.tag tag',
'tag.baseDataId = tmp.id and tag.tag = :category and tag.status = "active"'
)
->innerJoin(
'listdb.baseParam b0',
'b0.baseDataId = tmp.id
and ((b0.paramName = "role"
and (b0.paramValue = "public"))
or ((select count(*) from listdb.baseParam temp
where temp.baseDataId = tmp.id and paramName = "role" )=0))
or (b0.paramName = "role" and b0.paramValue = "public" and tmp.owner = :ownerId)'
)
->leftJoin(
'listdb.baseParam b1',
'b1.baseDataId = tmp.id and b1.paramName="duration" and b1.status = "active"'
)
->leftJoin(
'listdb.baseParam b2',
'b2.baseDataId = tmp.id and b2.paramName="itemCount" and b2.status = "active"'
)
->leftJoin(
'listdb.baseParam b3',
'b3.baseDataId = tmp.id and b3.paramName="previewUrl" and b3.status = "active"'
)
->leftJoin('assetdb.baseData asst', 'asst.id = b3.paramValue and asst.status = "active"')
->where('tmp.status = "active" and tmp.application = "template" and tmp.role = "public"')
->groupBy('tmp.id')
->orderBy(['tmp.upTime' => SORT_DESC]);
and my second query is this..
$query2 = new Query();
$query2->params([':category' => $category, ':ownerId' => $ownerId]);
$query2->select('tmp.id, tmp.title , tmp.description, asst.thumbAssetUrl, b1.paramValue as duration, b2.paramValue as clips, asst.fileUrl as video')
->from('listdb.baseData tmp')
->innerJoin(
'listdb.tag tag',
'tag.baseDataId = tmp.id and tag.tag = :category and tag.status = "active"'
)
->innerJoin(
'listdb.baseParam b0',
'b0.baseDataId = tmp.id
and ((b0.paramName = "role"
and (b0.paramValue = "private" or b0.paramValue = "" and b0.paramValue != "public"))
or ((select count(*) from listdb.baseParam temp
where temp.baseDataId = tmp.id and paramName = "role" )=0))
or (b0.paramName = "role" and b0.paramValue = "public" and tmp.owner = :ownerId)'
)
->leftJoin(
'listdb.baseParam b1',
'b1.baseDataId = tmp.id and b1.paramName="duration" and b1.status = "active"'
)
->leftJoin(
'listdb.baseParam b2',
'b2.baseDataId = tmp.id and b2.paramName="item_count" and b2.status = "active"'
)
->leftJoin(
'listdb.base_parambaseParameter b3',
'b3.baseDataId = tmp.id and b3.paramName="previewUrl" and b3.status = "active"'
)
->leftJoin('assetdb.baseData asst', 'asst.id = b3.paramValue and asst.status = "active"')
->innerJoin('listdb.childRestricted cr', 'cr.baseDataId = tmp.id and cr.status = "active" and cr.owner = :ownerId')
->where('tmp.status = "active" and tmp.application = "template" and tmp.role = "private"')
->groupBy('tmp.id')
->orderBy(['tmp.upTime' => SORT_DESC]);
i tried using this union
$query = $query2->union($query1, false);
but it seems that it does not unite the two queries properly because this causes the results to double. What seems to be the problem with this. Thanks in advance.

Try this:
$unionQuery = (new \yii\db\Query())
->from(['dummy_name' => $query1->union($query2)]);
print_r($unionQuery);
More detail on Official Site

Related

How conversion mysql query into yii2

Select tickets.id with calendar_date is null if last tickets.p_id(child row) calendar_date is null.
I want to convert this query in yii2 search model:
mysql query:
`SELECT b.ticket_id FROM (SELECT a.ticket_id FROM (
SELECT t.id AS ticket_id FROM tech_support.tickets t
WHERE t.tree_status_id = 2 AND t.p_id IS NULL) a
LEFT JOIN tech_support.tickets tt ON tt.p_id = a.ticket_id
WHERE tt.p_id IS NULL) b
LEFT JOIN tech_support.tickets ttt ON ttt.id = b.ticket_id WHERE
ttt.calendar_date IS NULL UNION ALL
SELECT b.maxid FROM (SELECT a.maxid, tt.calendar_date FROM (
SELECT MAX(t.id) AS maxid FROM tech_support.tickets t WHERE
t.tree_status_id = 2 GROUP BY t.p_id) a
LEFT JOIN tech_support.tickets tt ON tt.id = a.maxid) b
WHERE b.calendar_date IS NULL;`
yii2 code:
$subQuery = Tickets::find()
->select(new Expression('id as ticket_id'))
->where('tree_status_id = 2')
->andWhere('p_id is null')
->alias('a');
$subQuery->leftJoin('tickets', 'tickets.p_id = a.ticket_id')
->where('tickets.p_id is null')->all();
$query1 = (new \yii\db\Query())
->select(new Expression('id as ticket_id'))
->from($subQuery)
->where('p_id is null')
->alias('b');
$query1->leftJoin(['ttt' => 'tickets'], 'ttt.id =
b.ticket_id')
->where('ttt.calendar_date IS NULL');
$subQuery2 = Tickets::find()
->select(new Expression('MAX(tickets.id) as maxid'))
->where('tree_status_id = 2')
->groupBy(['p_id'])
->alias('a');
$subQuery2->leftJoin(['tt' => 'tickets'], 'tt.id = a.maxid')
->all();
$query2 = (new \yii\db\Query())
->select('maxid')
->from($subQuery2);
$query1->union($query2);
$query1->where('calendar_date is null');
Error Info:
Integrity constraint violation – yii\db\IntegrityException
Please help me.
Result:
//----------------query1------------------------------
$query = (new \yii\db\Query())
->select('t.id as ticket_id')
->from(['t' => 'tickets'])
->where('t.tree_status_id = 2')
->andWhere('t.p_id is null');
$subQuery = (new \yii\db\Query())
->select('a.ticket_id')
->from(['a' => $query]);
$subQuery->leftJoin(['tt' => 'tickets'], 'tt.p_id = a.ticket_id')
->where('tt.p_id is null');
$query1 = (new \yii\db\Query())
->select('b.ticket_id')
->from(['b' => $subQuery]);
$query1->leftJoin(['ttt' => 'tickets'], 'ttt.id = b.ticket_id')
->where('ttt.calendar_date IS NULL');
//----------------query2------------------------------
$subQuery2 = (new \yii\db\Query())
->select('MAX(t.id) as maxid')
->from(['t' => 'tickets'])
->where('t.tree_status_id = 2')
->groupBy(['t.p_id']);
$query2 = (new \yii\db\Query())
->select(['a.maxid', 'tt.calendar_date'])
->from(['a' => $subQuery2]);
$query2->leftJoin(['tt' => 'tickets'], 'tt.id = a.maxid');
$query3 = (new \yii\db\Query())
->select('b.maxid')
->from(['b' => $query2]);
$query3->leftJoin(['ttt' => 'tickets'], 'ttt.id = b.maxid')
->where('ttt.calendar_date IS NULL');
//----------------union queries------------------------------
$unionQuery = (new \yii\db\Query())
->from([$query1->union($query3, true)]);

Column 'available_for_order' in where clause is ambiguous

I'm strugling with this query within prestashop , i know it could be easily fixed by changing to sa.available_for_order but this way it breaks the logic of other core files ,
is there any other way around to fix this without renaming available_for_order to sa.available_for_order ,
SELECT
a.`id_product`,
b.`name` AS `name`,
`reference`,
a.`price` AS `price`,
sa.`active` AS `active`,
`newfield`,
shop.`name` AS `shopname`,
a.`id_shop_default`,
image_shop.`id_image` AS `id_image`,
cl.`name` AS `name_category`,
sa.`price`,
0 AS `price_final`,
a.`is_virtual`,
pd.`nb_downloadable`,
sav.`quantity` AS `sav_quantity`,
sa.`active`,
IF(sav.`quantity` <= 0, 1, 0) AS `badge_danger`,
sa.`available_for_order` AS `available_for_order`
FROM
`ps_product` a
LEFT JOIN
`ps_product_lang` b
ON
(
b.`id_product` = a.`id_product` AND b.`id_lang` = 1 AND b.`id_shop` = 1
)
LEFT JOIN
`ps_stock_available` sav
ON
(
sav.`id_product` = a.`id_product` AND sav.`id_product_attribute` = 0 AND sav.id_shop = 1 AND sav.id_shop_group = 0
)
JOIN
`ps_product_shop` sa
ON
(
a.`id_product` = sa.`id_product` AND sa.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_category_lang` cl
ON
(
sa.`id_category_default` = cl.`id_category` AND b.`id_lang` = cl.`id_lang` AND cl.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_shop` shop
ON
(
shop.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_image_shop` image_shop
ON
(
image_shop.`id_product` = a.`id_product` AND image_shop.`cover` = 1 AND image_shop.id_shop = a.id_shop_default
)
LEFT JOIN
`ps_image` i
ON
(
i.`id_image` = image_shop.`id_image`
)
LEFT JOIN
`ps_product_download` pd
ON
(pd.`id_product` = a.`id_product`)
WHERE
1 AND `available_for_order` = 1
ORDER BY
a.`id_product` ASC
LIMIT 0, 50
PRESTASHOP
public function __construct()
{
parent::__construct();
$this->_select .= ',sa.`available_for_order` AS `available_for_order`, ';
$this->fields_list['sa!available_for_order'] = array(
'title' => $this->l('Available for order'),
'width' => 90,
'active' => 'available_for_order',
'filter_key' => 'sa!available_for_order',
'type' => 'bool',
'align' => 'center',
'orderby' => false
);
}
Modify your fields list to use having filter.
$this->fields_list['available_for_order'] = array(
'title' => $this->l('Available for order'),
'width' => 90,
'active' => 'available_for_order',
'filter_key' => 'available_for_order',
'havingFilter' => true,
'type' => 'bool',
'align' => 'center',
'orderby' => false
);
This will use HAVING instead of WHERE in query.
WHERE clause does not work on column aliases but HAVING does.
The column available_for_order must be in more than one of the tables. Just qualify the column name, as you do in the select:
WHERE 1 AND sa.available_for_order = 1
------------^

Multiple rows in a select with OR

I have this query and when I add a OR, return multiples rows, how I can fix this? I need another left join or Right join?
SELECT `images`.`id` as `id_image`, `images_lang`.`title` as `title`, `images_lang`.`autor` as `author`, `media_lang`.`file`, `category_lang`.`title` as `category`
FROM `images`
JOIN `images_lang` ON `images_lang`.`id_images` = `images`.`id`
JOIN `category_lang` ON `images`.`id_category` = `category_lang`.`id_category`
JOIN `media` ON `images`.`id` = `media`.`id_item`
JOIN `media_lang` ON `media`.`id` = `media_lang`.`id_media`
JOIN `relation` ON `relation`.`from_id` = `images`.`id`
JOIN `tag` ON `tag`.`id` = `relation`.`to_id`
JOIN `tag_lang` ON `tag`.`id` = `tag_lang`.`id_lang`
WHERE `media`.`table` = 'images'
AND `media_lang`.`id_lang` = '1'
AND `images_lang`.`id_lang` = '1'
AND `category_lang`.`id_lang` = '1'
AND `images`.`active` = 1
AND `relation`.`type` = 2
AND `tag_lang`.`id_lang` = '1'
AND `tag_lang`.`slug` = 'pa-am-oli'
OR `tag_lang`.`slug` = 'playa'
LIMIT 9
and the code in codeigniter, but I don´t how add the or after the and ($keywords is an array for filter the elements)
$this->db->select('images.id as id_image, images_lang.title as title, images_lang.autor as author, media_lang.file, category_lang.title as category');
$this->db->from($this->table);
$this->db->join($this->table.'_lang',$this->table.'_lang.id_images = '.$this->table.'.id');
$this->db->join('category_lang',$this->table.'.id_category = category_lang.id_category');
$this->db->join('media',$this->table.'.id = media.id_item');
$this->db->join('media_lang','media.id = media_lang.id_media');
$this->db->where('media.table',$this->table);
$this->db->where('media_lang.id_lang',$id_lang);
$this->db->where($this->table.'_lang.id_lang', $id_lang);
$this->db->where('category_lang.id_lang', $id_lang);
$this->db->where('images.active', 1);
if($category){
$this->db->where('category_lang.title', $category);
}
if($keywords){
$this->db->join('relation', 'relation.from_id = '.$this->table.'.id');
$this->db->join('tag', 'tag.id = relation.to_id');
$this->db->join('tag_lang', 'tag.id = tag_lang.id_lang');
$this->db->where('relation.type', _IMAGES_2_TAGS_);
$this->db->where('tag_lang.id_lang', $id_lang);
foreach($keywords as $tag){
$this->db->or_where('tag_lang.slug', $tag);
}
}
if($from || $limit)
{
$this->db->limit((int)$limit, (int)$from);
}
$query = $this->db->get();
return $query->result_array();
I solved the query adding this (and a Select Distinct)
AND (`tag_lang`.`slug` = 'playa'
OR `tag_lang`.`slug` = 'pa-am-oli')
How I can add this in codeigniter?
I don't get what you need exactly, but if you want have just one line as a return by filtering using OR
In your case you should do the following:
WHERE (`media`.`table` = 'images' OR `tag_lang`.`slug` = 'playa')
AND (`media_lang`.`id_lang` = '1' OR `tag_lang`.`slug` = 'playa')
and so on, I hope that helps you and good luck!
Astute use of parentheses would solve your problem, but this is easier to read...
SELECT i.id id_image
, il.title
, il.autor author
, ml.file
, cl.title category
FROM images i
JOIN images_lang il
ON il.id_images = i.id
JOIN category_lang cl
ON cl.id_category = i.id_category
JOIN media m
ON m.id_item = i.id
JOIN media_lang ml
ON ml.id_media = m.id
JOIN relation r
ON r.from_id = i.id
JOIN tag t
ON t.id = r.to_id
JOIN tag_lang tl
ON tl.id_lang = t.id
WHERE m.table = 'images'
AND ml.id_lang = 1
AND il.id_lang = 1
AND cl.id_lang = 1
AND i.active = 1
AND r.type = 2
AND tl.id_lang = 1
AND tl.slug IN('pa-am-oli','playa')
LIMIT 9
... however, note that LIMIT without ORDER BY is fairly meaningless.

How to implement ON ( ... OR ...) mysql query in doctrine2 queryBuilder

I have a SQL query in MYSQL:
For example
SELECT s.* FROM vplanning.cities as c1
INNER JOIN vplanning.cities as c2
ON (c1.id = c2.area_id)
INNER JOIN vplanning.storages as s
ON (s.city_id = c2.id OR s.city_id = c1.id)
WHERE c1.id = 109;
In doctrine I can write something like this (from my work code):
$query = $em->getRepository('VplanningPageBundle:Storage')
->createQueryBuilder('s')
->innerJoin('s.city', 'c1')
->innerJoin('c1.area', 'c2')
->innerJoin('s.storagestype', 'st')
->where('c2.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('s.adress')
->getQuery();
As you can see, I show my relation in
->innerJoin('s.city', 'c1')
but I need also relation like
->innerJoin('s.city', 'c2')
with this condition:
ON (s.city_id = c2.id OR s.city_id = c1.id)
But it throws this error:
Error: 'c2' is already defined
c1 and c2 are the same entity and have a inner relation.
Try this:
$repository = $em->getRepository('VplanningPageBundle:Storage');
$qb = $repository->createQueryBuilder('storage');
//We can now use the expr()
$qb->join('storage.city', 'city', Join::WITH)
->join('city.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress');
$query = $qb->getQuery();
Try smth like this
$qb = $this->getRepository('VplanningPageBundle:City')->createQueryBuilder('c');
$qb->leftJoin('c.area', 'a')
->join('c.storage', 's', Join::ON, $qb->expr()->orX($qb->expr()->eq('c.id', 's.id'), $qb->expr()->eq('a.id', 's.id')))
->innerJoin('s.storagestype', 'st')
->where('c.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1,
))
->orderBy('s.adress')
->getQuery()
;
The solution of the problem was very difficult as for me, I have to study it :)
This is a answer for my question from some forum board:
$qb = $em->getRepository('VplanningPageBundle:Storage')->createQueryBuilder('storage');
$query = $qb->join('storage.city', 'city1', Join::WITH)
->leftJoin('city1.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->leftJoin('storage.city', 'city2', Join::WITH, $qb->expr()->eq('city2.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->andWhere($qb->expr()->orX($qb->expr()->isNotNull('city2'), $qb->expr()->isNotNull('area')))
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress')
->getQuery();

Update mysql table with data from multiple tables

I have the following query and I would like to make it so if there's a duplicate key it updates the values
INSERT INTO totalData (pageId, dateScanned, totalPageLikes, totalTalkingAbout, totalPos, totalNeg, totalFemales, totalMales, totalStrongPositives, totalPositives, totalWeakPositives, totalNeutrals, totalWeakNegatives, totalNegatives, totalStrongNegatives, totalStatuses, totalStatusLikes, totalStatusShares, totalComments, totalUniqueCommenters)
SELECT pages.pageId, pages.dateScanned, pages.likes, pages.talkingAbout,
SUM(commentTags.tag LIKE '%positive%') AS positive,
SUM(commentTags.tag LIKE '%negative%') AS negative,
SUM(comments.gender = 'female') AS females,
SUM(comments.gender = 'male') AS males,
SUM(commentTags.tag = 'strong_positive') AS strongPositives,
SUM(commentTags.tag = 'positive') AS positives,
SUM(commentTags.tag = 'weak_positive') AS weakPositives,
SUM(commentTags.tag = 'neutral') AS neutrals,
SUM(commentTags.tag = 'weak_negative') AS weakNegatives,
SUM(commentTags.tag = 'negative') AS negatives,
SUM(commentTags.tag = 'strong_negative') AS strongNegatives,
COUNT(DISTINCT statuses.statusId) AS totalStatuses,
SUM(DISTINCT statuses.likesCount) AS totalLikesCount,
SUM(DISTINCT statuses.sharesCount) AS totalSharesCount,
COUNT(DISTINCT comments.commentId) AS totalComments,
COUNT(DISTINCT comments.userName) AS uniqueUsers
FROM pages
JOIN statuses ON pages.pageId = statuses.pageId AND pages.dateScanned = statuses.dateScanned
JOIN comments ON comments.statusID = statuses.statusId
JOIN commentTags ON comments.commentId = commentTags.commentId
WHERE pages.pageId = '115798033817' AND pages.dateScanned = '2013-11-05'
I tried the ON DUPLICATE KEY UPDATE and this is how I further modified the query
ON DUPLICATE KEY UPDATE
totalData.pageId = pageId, totalData.dateScanned = dateScanned,
totalData.totalPageLikes = totalPageLikes, totalData.totalTalkingAbout = totalTalkingAbout,
totalData.totalPos = positive, totalData.totalNeg = negative, totalData.totalFemales = females,
totalData.totalMales = males, totalData.totalStrongPositives = strongPositives,
totalData.totalPositives = positives, totalData.totalWeakPositives = weakPositives,
totalData.totalNeutrals = neutrals, totalData.totalWeakNegatives = weakNegatives,
totalData.totalNegatives = negatives, totalData.totalStrongNegatives = strongNegatives,
totalData.totalStatuses = totalStatuses, totalData.totalStatusLikes = totalLikesCount,
totalData.totalStatusShares = totalSharesCount, totalData.totalComments = totalComments,
totalData.totalUniqueCommenters = uniqueUsers ;
But when i run the query it says Unknown column 'positive' in field list.
Got it, I had to use the VALUES() function so the ON DUPLICATE KEY UPDATE part of the query becomes like the following
ON DUPLICATE KEY UPDATE
totalPageLikes = VALUES(totalPageLikes), totalTalkingAbout = VALUES(totalTalkingAbout),
totalPos = VALUES(totalPos), totalNeg = VALUES(totalNeg), totalFemales = VALUES(totalFemales), totalMales = VALUES(totalMales),
totalStrongPositives = VALUES(totalStrongPositives), totalPositives = VALUES(totalPositives), totalWeakPositives = VALUES(totalWeakPositives),
totalNeutrals = VALUES(totalNeutrals), totalWeakNegatives = VALUES(totalWeakNegatives), totalNegatives = VALUES(totalNegatives), totalStrongNegatives = VALUES(totalStrongNegatives),
totalStatuses = VALUES(totalStatuses), totalStatusLikes = VALUES(totalStatusLikes), totalStatusShares = VALUES(totalStatusShares),
totalComments = VALUES(totalComments), totalUniqueCommenters = VALUES(totalUniqueCommenters) ";