view select cannot contain from clause - mysql

I have a SQL Query. When I run it executes successfully, but when i was trying to create a view with the query it shows create a view with each subquery.
SOS.
SELECT `product_category_vendor_id`,
ct1.category_id,
ct1.category_name,
c1.`product_id`,
p1.product_name,
c1.`vendor_id`,
v1.vendor_name,
c1.`product_purchase_price`,
c1.product_vendor_qty,
d1.available
FROM (SELECT `product_category_vendor_id`,
a1.`product_id`,
a1.`vendor_id`,
a1.`product_purchase_price`,
b2.product_vendor_qty
FROM (SELECT `product_category_vendor_id`,
`product_id`,
`vendor_id`,
`product_purchase_price`
FROM tbl_inksand_product_category_vendor
WHERE product_category_vendor_id IN
(SELECT
Max(product_category_vendor_id) AS
`Product_Category_Vendor_Id`
FROM
tbl_inksand_product_category_vendor
WHERE (
product_category_vendor_status =
'A' )
GROUP BY product_id,
`vendor_id`
ORDER BY `product_id`))
AS a1
JOIN (SELECT `product_id`,
`vendor_id`,
Sum(`product_vendor_qty`) AS Product_Vendor_Qty
FROM tbl_inksand_product_category_vendor
GROUP BY product_id,
`vendor_id`
ORDER BY `product_id`) b2
ON a1.`product_id` = b2.`product_id`
AND a1.`vendor_id` = b2.`vendor_id`) c1
JOIN (SELECT `product_id`,
`vendor_id`,
Count(`item_id`) AS Available
FROM `tbl_inksand_item_dtls`
WHERE `product_item_status` = 'Not Sale'
GROUP BY `product_id`,
`vendor_id`) d1
ON c1.`product_id` = d1.`product_id`
AND c1.`vendor_id` = d1.`vendor_id`
JOIN tbl_inksand_vendor AS v1
ON c1.`vendor_id` = v1.`vendor_id`
JOIN tbl_inksand_product p1
ON p1.product_id = c1.`product_id`
JOIN tbl_inksand_category ct1
ON ct1.category_id = p1.category_id

Subqueries cannot be used in the FROM clause of a view.
Source: https://dev.mysql.com/doc/refman/5.0/en/view-restrictions.html
So yeah it was the right reccomendation to create seperate views.

Related

Why I can not join this query with Max date?

I have an issue with the following mySQL query where it fails when Max date is introduced as shown below.
I get the following error
Error Code: 1054. Unknown column 'order_items.ORDER_ITEM_ID' in 'where
clause'
SET #UserID = 160;
SET #OrderDateTime = '2018-11-13 09:23:45';
SELECT
order_items.ORDER_ID,
listing_region.LIST_REGION_REGION_ID,
listings.LISTING_ID,
order_items.ORDER_REQUIRED_DATE_TIME,
listings.LISTING_NICK_NAME,
order_items.ORDER_QUANTITY,
order_price.ORDER_PRICE_ID,
order_items.ORDER_PORTION_SIZE,
t.LATEST_DATE,
t.ORDER_STATUS
FROM order_status_change, order_items
INNER JOIN listings ON listings.LISTING_ID = order_items.ORDER_LISTING_ID
INNER JOIN listing_region ON listing_region.LIST_REGION_LISTING_ID = listings.LISTING_ID
INNER JOIN order_price ON order_price.ORDERP_ITEM_ID = order_items.ORDER_ITEM_ID
INNER JOIN
(
SELECT MAX(order_status_change.ORDER_STATUS_CHANGE_DATETIME) AS LATEST_DATE, order_status_change.ORDER_ITEM_ID, order_status_change.ORDER_STATUS
FROM order_status_change
WHERE order_status_change.ORDER_ITEM_ID = order_items.ORDER_ITEM_ID
) AS t ON order_status_change.ORDER_ITEM_ID = t.ORDER_ITEM_ID AND order_status_change.ORDER_STATUS_CHANGE_DATETIME = t.LATEST_DATE
WHERE ((order_items.ORDER_USER_ID = #UserID) AND DATE(order_items.ORDER_REQUIRED_DATE_TIME) = DATE(#OrderDateTime))
Any help ?
I have assumed you can join order_status_change on order_items.ID = order_status_change.ORDER_ITEM_ID
If that is valid then I think this will achieve what you are after:
SET #UserID = 160;
SET #OrderDateTime = '2018-11-13 09:23:45';
SELECT
order_items.ORDER_ID
, listing_region.LIST_REGION_REGION_ID
, listings.LISTING_ID
, order_items.ORDER_REQUIRED_DATE_TIME
, listings.LISTING_NICK_NAME
, order_items.ORDER_QUANTITY
, order_price.ORDER_PRICE_ID
, order_items.ORDER_PORTION_SIZE
, t.LATEST_DATE
, order_status_change.ORDER_STATUS
FROM order_items
INNER JOIN listings ON listings.LISTING_ID = order_items.ORDER_LISTING_ID
INNER JOIN listing_region ON listing_region.LIST_REGION_LISTING_ID = listings.LISTING_ID
INNER JOIN order_price ON order_price.ORDERP_ITEM_ID = order_items.ORDER_ITEM_ID
INNER JOIN order_status_change ON order_items.ID = order_status_change.ORDER_ITEM_ID
INNER JOIN (
SELECT
MAX( mc.ORDER_STATUS_CHANGE_DATETIME ) AS LATEST_DATE
, mc.ORDER_ITEM_ID
FROM order_status_change AS mc
GROUP BY
mc.ORDER_ITEM_ID
) AS t
ON order_status_change.ORDER_ITEM_ID = t.ORDER_ITEM_ID
AND order_status_change.ORDER_STATUS_CHANGE_DATETIME = t.LATEST_DATE
WHERE order_items.ORDER_USER_ID = #UserID
AND DATE( order_items.ORDER_REQUIRED_DATE_TIME ) = DATE( #OrderDateTime )
You need to avoid this in future:
FROM order_status_change , order_items
That comma between the 2 table names IS a join, but it is from an older syntax and it is LOWER in precedence than the other joins of your query. Also, by default this comma based join acts as an equivalent to a cross join which MULTIPLIES the number of rows. In brief, please do NOT USE commas between table names.
The other issue is that you were missing a group by clause and I believe you just want to get the "latest" date from this aggregation, once that is determined link back to that table to get the status relevant to that date. (i.e. you can't group by status in the subquery, otherwise you get the latest dateS (one for each status).
Here's a simplified version to illustrate the problem.
DROP TABLE IF exists t,t1;
create table t (id int);
create table t1(id int,dt date);
insert into t values (1),(2);
insert into t1 values (1,'2018-01-01'),(1,'2018-02-01'),(2,'2018-01-01');
select t.*,t2.maxdt
from t
join (select max(dt) maxdt,t1.id from t1 where t1.id = t.id) t2
on t2.id = t.id;
ERROR 1054 (42S22): Unknown column 't.id' in 'where clause'
You could group by in the sub query and then the on clause will come into play
select t.*,t2.maxdt
from t
join (select max(dt) maxdt,t1.id from t1 group by t1.id) t2
on t2.id = t.id;
+------+------------+
| id | maxdt |
+------+------------+
| 1 | 2018-02-01 |
| 2 | 2018-01-01 |
+------+------------+
2 rows in set (0.00 sec)
If you want an answer closer to your problem please add sample data and expected output to the question as text of to sqlfiddle.

MySQL select with group and one to many relations condition

For example have such structure:
CREATE TABLE clicks
(`date` varchar(50), `sum` int, `id` int)
;
CREATE TABLE marks
(`click_id` int, `name` varchar(50), `value` varchar(50))
;
where click can have many marks
So example data:
INSERT INTO clicks
(`sum`, `id`, `date`)
VALUES
(100, 1, '2017-01-01'),
(200, 2, '2017-01-01')
;
INSERT INTO marks
(`click_id`, `name`, `value`)
VALUES
(1, 'utm_source', 'test_source1'),
(1, 'utm_medium', 'test_medium1'),
(1, 'utm_term', 'test_term1'),
(2, 'utm_source', 'test_source1'),
(2, 'utm_medium', 'test_medium1')
;
I need to get agregated values of click grouped by date which contains all of selected values.
I make request:
select
c.date,
sum(c.sum)
from clicks as c
left join marks as m ON m.click_id = c.id
where
(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1') OR
(m.name = 'utm_term' AND m.value='test_term1')
group by date
and get 2017-01-01 = 700, but I want to get 100 which means that only click 1 has all of marks.
Or if condition will be
(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1')
I need to get 300 instead of 600
I found answer in getting distinct click_id by first query and then sum and group by date with condition whereIn, but on real database which is very large and has id as uuid this request executes extrimely slow. Any advices how to get it work propely?
You can achieve it using below queries:
When there are the three conditions then you have to pass the HAVING count(*) >= 3
SELECT cc.DATE
,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
SELECT id
FROM clicks AS c
LEFT JOIN marks AS m ON m.click_id = c.id
WHERE (
m.NAME = 'utm_source'
AND m.value = 'test_source1'
)
OR (
m.NAME = 'utm_medium'
AND m.value = 'test_medium1'
)
OR (
m.NAME = 'utm_term'
AND m.value = 'test_term1'
)
GROUP BY id
HAVING count(*) >= 3
) AS t ON cc.id = t.id
GROUP BY cc.DATE
When there are the three conditions then you have to pass the HAVING count(*) >= 2
SELECT cc.DATE
,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
SELECT id
FROM clicks AS c
LEFT JOIN marks AS m ON m.click_id = c.id
WHERE (
m.NAME = 'utm_source'
AND m.value = 'test_source1'
)
OR (
m.NAME = 'utm_medium'
AND m.value = 'test_medium1'
)
GROUP BY id
HAVING count(*) >= 2
) AS t ON cc.id = t.id
GROUP BY cc.DATE
Demo: http://sqlfiddle.com/#!9/fe571a/35
Hope this works for you...
You're getting 700 because the join generates multiple rows for the different IDs. There are 3 rows in the mark table with ID=1 and sum=100 and there are two rows with ID=2 and sum=200. On doing the join where shall have 3 rows with sum=100 and 2 rows with sum=200, so adding these sum gives 700. To fix this you have to aggregate on the click_id too as illustrated below:
select
c.date,
sum(c.sum)
from clicks as c
inner join (select * from marks where (name = 'utm_source' AND
value='test_source1') OR (name = 'utm_medium' AND value='test_medium1')
OR (name = 'utm_term' AND value='test_term1')
group by click_id) as m
ON m.click_id = c.id
group by c.date;
DEMO SQL FIDDLE
I found the right way myself, which works on large amounts of data
The main goal is to make request generate one table with subqueries(conditions) which do not depend on amount of data in results, so the best way is:
select
c.date,
sum(c.sum)
from clicks as c
join marks as m1 ON m1.click_id = c.id
join marks as m2 ON m2.click_id = c.id
join marks as m3 ON m3.click_id = c.id
where
(m1.name = 'utm_source' AND m1.value='test_source1') AND
(m2.name = 'utm_medium' AND m2.value='test_medium1') AND
(m3.name = 'utm_term' AND m3.value='test_term1')
group by date
So we need to make as many joins as many conditions we have

MySQL Getting row numbers of table inside subquery

I have one query where I need to have number of rows of an table by particular ID:
SELECT
(CAST(`ot`.`value` AS DECIMAL(6,2))) AS `value`,
`op`.`orders_id`,
(
SELECT
COUNT(1) AS `total`
FROM
(
SELECT
`op2`.`concert_date`
FROM
`orders_products` `op2`
WHERE
`op2`.`orders_id` = `op`.`orders_id`
AND
`op2`.`concert_date` <> ''
GROUP BY CONCAT(`op2`.`concert_date`,' ',`op2`.`concert_time`)
) AS `e`
) AS `devider`
FROM
`categories` `c`
JOIN `products` `p` ON `p`.`section_id` = `c`.`section_id`
JOIN `orders_products` `op` ON `op`.`products_id` = `p`.`products_id`
JOIN `orders_total` `ot` ON `ot`.`orders_id` = `op`.`orders_id`
WHERE
`c`.`section_id` = 25
AND
`p`.`product_type` IN ('P')
AND
`ot`.`class` IN ('ot_shipping')
GROUP BY `op`.`orders_id`
The main problem is that I getting error
#1054 - Unknown column 'op.orders_id' in 'where clause'
And can't run this. I have separated query in my loop but that made performance issue and want to push it in one query. Any idea?
try removing sub-sub query and use COUNT(DISTINCT ..)
SELECT
(CAST(`ot`.`value` AS DECIMAL(6,2))) AS `value`,
`op`.`orders_id`,
(
SELECT
COUNT(DISTINCT CONCAT(`op2`.`concert_date`,' ',`op2`.`concert_time`))
FROM
`orders_products` `op2`
WHERE
`op2`.`orders_id` = `op`.`orders_id`
AND
`op2`.`concert_date` <> ''
) AS `devider`
FROM
`categories` `c`
JOIN `products` `p` ON `p`.`section_id` = `c`.`section_id`
JOIN `orders_products` `op` ON `op`.`products_id` = `p`.`products_id`
JOIN `orders_total` `ot` ON `ot`.`orders_id` = `op`.`orders_id`
WHERE
`c`.`section_id` = 25
AND
`p`.`product_type` IN ('P')
AND
`ot`.`class` IN ('ot_shipping')
GROUP BY `op`.`orders_id`
and you don't even need subquery or concat as long concert_date or concert_time is null
SELECT
(CAST(`ot`.`value` AS DECIMAL(6,2))) AS `value`,
`op`.`orders_id`,
COUNT(DISTINCT `op`.`concert_date`, `op`.`concert_time`) AS `devider`
FROM
`categories` `c`
JOIN `products` `p` ON `p`.`section_id` = `c`.`section_id`
LEFT JOIN `orders_products` `op` ON `op`.`products_id` = `p`.`products_id`
JOIN `orders_total` `ot` ON `ot`.`orders_id` = `op`.`orders_id`
WHERE
`c`.`section_id` = 25
AND
`p`.`product_type` IN ('P')
AND
`ot`.`class` IN ('ot_shipping')
GROUP BY `op`.`orders_id`
In this subquery:
SELECT
`op2`.`concert_date`
FROM
`orders_products` `op2`
WHERE
`op2`.`orders_id` = `op`.`orders_id`
AND
`op2`.`concert_date` <> ''
GROUP BY CONCAT(`op2`.`concert_date`,' ',`op2`.`concert_time`)
you are not selecting op as table.
Should be:
SELECT
`op2`.`concert_date`
FROM
`orders_products` `op2`, `orders_products` `op`
WHERE
`op2`.`orders_id` = `op`.`orders_id`
AND
`op2`.`concert_date` <> ''
GROUP BY CONCAT(`op2`.`concert_date`,' ',`op2`.`concert_time`)
Beside this you are making an implicit join while you should use explicit even here and the subquery should become:
SELECT
`op2`.`concert_date`
FROM
`orders_products` `op2` JOIN `orders_products` `op`
ON
`op2`.`orders_id` = `op`.`orders_id`
WHERE
`op2`.`concert_date` <> ''
GROUP BY CONCAT(`op2`.`concert_date`,' ',`op2`.`concert_time`)

Mysql Loop By Query Result

I have this query that produces a list of foreign keys:
SELECT ad_id
FROM ads AS i
INNER JOIN ads_earnings AS e
ON i.ad_id = e.earning_ad_id
GROUP BY i.ad_id
I want to use that as the parameter for this query in a loop:
INSERT INTO ads_stats_traffic
(traffic_ad_id,traffic_country_id,traffic_paid,traffic_verified,traffic_total)
(
SELECT earning_ad_id, earning_country_id, earning_paid, SUM(earning_verified), COUNT(earning_id)
FROM ads_earnings
WHERE earning_ad_id = ?
GROUP BY earning_paid, earning_country_id
)
How do I do that?
Using a nested subquery with in should work:
INSERT INTO ads_stats_traffic
(traffic_ad_id,traffic_country_id,traffic_paid,traffic_verified,traffic_total)
(
SELECT earning_ad_id, earning_country_id, earning_paid, SUM(earning_verified), COUNT(earning_id)
FROM ads_earnings
WHERE earning_ad_id in
(
SELECT ad_id
FROM ads AS i
INNER JOIN ads_earnings AS e
ON i.ad_id = e.earning_ad_id
GROUP BY i.ad_id
)
GROUP BY earning_paid, earning_country_id
)

MySQL error: duplicate column

I'm having a bit of a problem with the following MySQL query and I can't find the source of it.
MySQL tells me that
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name
'annonce_dispo_id'
SELECT MAX(max_price) AS `max_price`,
COUNT(*) AS `nb_annonces`,
SUM(nb_dispo) AS `nb_dispo`
FROM
(SELECT `annonce`.`id`,
CEIL(MAX(price)*1.16) AS `max_price`,
COUNT(DISTINCT annonce.id) AS `nb_annonces`,
COUNT(annonce_dispoo.annonce_dispo_id) AS `nb_dispo`,
`annonce_dispo1`.*,
`annonce_dispo2`.*
FROM `annonce`
LEFT JOIN `annonce_dispo` AS `annonce_dispoo` ON (annonce_dispoo.annonceId = annonce.id
AND STR_TO_DATE(annonce_dispoo.dispo_date, '%d/%m/%Y') >= CURDATE())
INNER JOIN `annonce_dispo` AS `annonce_dispo1` ON annonce.id = annonce_dispo1.annonceId
INNER JOIN `annonce_dispo` AS `annonce_dispo2` ON annonce.id = annonce_dispo2.annonceId
WHERE ((annonce.city IN
(SELECT `cities`.`id`
FROM `cities`
WHERE (cities.label LIKE 'lyon%'))
OR annonce.zipcode = 'lyon')
OR (annonce.city LIKE '28674'
OR annonce.zipcode = '28674'))
AND (annonce_dispo1.dispo_date = '27/05/2014')
AND (annonce_dispo1.disponibility = 'available')
AND (annonce_dispo2.dispo_date = '31/05/2014')
AND (annonce_dispo2.disponibility = 'available')
AND (annonce.visible = 1)
AND (annonce.completed = 1)
GROUP BY `annonce`.`id` HAVING (nb_dispo >= 1)) AS `t`
I thought gave a different alias for the table in each JOIN I use them in, and can't really put my finger on what else is possible to output such an error.
Don't select annonce_dispo1.* and annonce_dispo2.* in your subquery, duplicated column names are being returned. Instead select the fields you need and alias accordingly.
SELECT MAX(max_price) AS `max_price`,
COUNT(*) AS `nb_annonces`,
SUM(nb_dispo) AS `nb_dispo`
FROM
(SELECT `annonce`.`id`,
CEIL(MAX(price)*1.16) AS `max_price`,
COUNT(DISTINCT annonce.id) AS `nb_annonces`,
COUNT(annonce_dispoo.annonce_dispo_id) AS `nb_dispo`,
`annonce_dispo1`.field, `annonce_dispo1`.otherfield,
`annonce_dispo1`.field as field2, `annonce_dispo1`.otherfield as otherfield2
FROM `annonce`
LEFT JOIN `annonce_dispo` AS `annonce_dispoo` ON (annonce_dispoo.annonceId = annonce.id
AND STR_TO_DATE(annonce_dispoo.dispo_date, '%d/%m/%Y') >= CURDATE())
INNER JOIN `annonce_dispo` AS `annonce_dispo1` ON annonce.id = annonce_dispo1.annonceId
INNER JOIN `annonce_dispo` AS `annonce_dispo2` ON annonce.id = annonce_dispo2.annonceId
WHERE ((annonce.city IN
(SELECT `cities`.`id`
FROM `cities`
WHERE (cities.label LIKE 'lyon%'))
OR annonce.zipcode = 'lyon')
OR (annonce.city LIKE '28674'
OR annonce.zipcode = '28674'))
AND (annonce_dispo1.dispo_date = '27/05/2014')
AND (annonce_dispo1.disponibility = 'available')
AND (annonce_dispo2.dispo_date = '31/05/2014')
AND (annonce_dispo2.disponibility = 'available')
AND (annonce.visible = 1)
AND (annonce.completed = 1)
GROUP BY `annonce`.`id` HAVING (nb_dispo >= 1)) AS `t`
See here for an example that doesn't work:
http://sqlfiddle.com/#!2/9bb13/1
The problem is that you are selecting all columns in the tables annonce_dispo1 and annonce_dispo2.
The fact that you have attributed different table names doesn't mean that there aren't duplicate column names.
I mean, you should use [Table name].[column name]
Example:
(SELECT `annonce`.`id`,
CEIL(MAX(price)*1.16) AS `max_price`,
COUNT(DISTINCT annonce.id) AS `nb_annonces`,
COUNT(annonce_dispoo.annonce_dispo_id) AS `nb_dispo`,
`annonce_dispo1`.annonce_dispo_id AS `column1`,
`annonce_dispo2`.annonce_dispo_id AS `column2`
I hope I've helped