How to access subquery table in the main query with MySQL? - mysql

select m1.id, m1.status, at.view_data, at.view_graph, ta.tag_string
from
access_tbl at, image_campaign_tbl m1
RIGHT JOIN
(select
GROUP_CONCAT(t.name) as tag_string , c.image_campaign_id
from campaign_tags_tbl c,tag_tbl t
where c.tag_id=t.id
$tag_q
group by c.image_campaign_id
) as ta
ON ta.image_campaign_id=m1.id
where
m1.client_id =$client_id
and m1.client_id = at.client_id
$prev_filter
limit $start,$end;
Error message:
in LOGS: DBD::mysql::db selectall_arrayref failed: Unknown column 't.name' in 'where clause' at /home/sakthi/rtads/Project/pm/Image/UI.pm line 2536.**
In Perl Module, I'm passing the same value of $tag_q to the $prev_filter to get the Pagination of filter based on TAGS values in the next page
if ( $prev_filter eq '' ) {
$prev_filter =
$search_clist_q . ' '
. $tag_q . ' '
}
From the error msg, I got the error which I'm doing. Since I'm trying to access the table of subquery in the main query, this error is happening.
So I want to know how to access the tag_string(or)t.name outside the subquery.

First of all, i suggest you to avoid use of old school syntax for jointures (FROM table1, table2,... WHERE table1.column1 = table2.column2 AND ...).
Here is the query that seems to return what you're looking for:
SELECT IC.id
,IC.status
,A.view_data
,A.view_graph
,TA.tag_string
FROM access_tbl A
INNER JOIN image_campaign_tbl IC ON IC.client_id = A.client_id
AND IC.client_id = $client_id
RIGHT JOIN (SELECT CT.image_campaign_id
,GROUP_CONCAT(T.name) AS [tag_string]
FROM campaign_tags_tbl CT
INNER JOIN tag_tbl T ON T.id = CT.tag_id
GROUP BY CT.image_campaign_id) TA ON TA.image_campaign_id = IC.id
WHERE <Your filters here>
LIMIT $start, $end
Hope this will help you.

Related

Unexpected character. (near ":" at position 1093)

I have moved CMS to a new server and I had an error on some pages:
Unable to execute SELECT statement [SELECT SQL_CALC_FOUND_ROWS DISTINCT shop_products.id, shop_products.user_id, shop_products.route_id, shop_products.external_id, shop_products.active, shop_products.hit, shop_products.hot, shop_products.action, shop_products.archive, shop_products.brand_id, shop_products.category_id, shop_products.related_products, shop_products.old_price, shop_products.created, shop_products.updated, shop_products.views, shop_products.added_to_cart_count, shop_products.enable_comments, shop_products.tpl, shop_products_i18n.id, shop_products_i18n.locale, shop_products_i18n.name, shop_products_i18n.short_description, shop_products_i18n.full_description, shop_products_i18n.meta_title, shop_products_i18n.meta_description, shop_products_i18n.meta_keywords, IF(sum(shop_product_variants.stock) > 0, 1, 0) AS allstock FROM shop_products INNER JOIN shop_product_categories ON (shop_products.id=shop_product_categories.product_id) INNER JOIN shop_category ON (shop_products.category_id=shop_category.id) INNER JOIN shop_products_i18n ON (shop_products.id=shop_products_i18n.id AND shop_products_i18n.locale = :p1) INNER JOIN shop_product_variants ON (shop_products.id=shop_product_variants.product_id) LEFT JOIN shop_brands ON (shop_products.brand_id=shop_brands.id) WHERE shop_product_categories.category_id=:p2 AND shop_products.active=:p3 AND shop_products.archive=:p4 AND shop_category.active=:p5 GROUP BY shop_products.id ORDER BY allstock DESC,shop_product_variants.price DESC,shop_products.id DESC LIMIT 32]
I also fulfilled this request in PhpmyAdmin and got an errors of such a type:
Unexpected character. (near ":" at position 1093)
Please tell me, why there is no such error on one server, but on another server it's displayed?
It complains about this join
INNER JOIN shop_products_i18n ON (shop_products.id=shop_products_i18n.id AND shop_products_i18n.locale = :p1)
make sure you're passing p1 as an argument or join on a specific column instead of passing an argument?

Add join to SQL query

I need to add a join 'level' to a pre-existing SQL query... unfortunately I keep getting errors with this query. I'm proabably falling somewhere but I cannot understand how to fix it.
The original query is the following:
SELECT
noleggio.*,
nome AS convenzionato
FROM
anag_convenzionati
RIGHT JOIN (SELECT
noleggio.*, targa, dc_standard AS dcstandard
FROM
veicoli_contratti
RIGHT JOIN (SELECT
noleggio.*,
nome AS assicurazione_pagante
FROM
anag_assicurazioni
RIGHT JOIN (SELECT
fatt_sconto_noleggio,
fatt_prezzo_noleggio,
id AS idnoleggio,
numero,
serie,
id_convenzionato,
stato_noleggio,
modalita_noleggio,
conducente,
locatario,
locazione_in_proprio,
id_assicurazione_pagante,
id_veicolo,
giorni,
fatt_giorni_noleggio,
fatt_prezzo_totale_noleggio,
data_pagamento_cliente_a_convenzionato,
ore_manodopera,
IF(locazione_in_proprio = 1, conducente, locatario) AS cedente
FROM
noleggio_veicoli
WHERE
((data_cancellazione IS NULL) OR (data_cancellazione = ''))
) AS noleggio ON noleggio.id_assicurazione_pagante = anag_assicurazioni.id
) AS noleggio ON noleggio.id_veicolo = veicoli_contratti.id
) AS noleggio ON noleggio.id_convenzionato = anag_convenzionati.id;
I need to join the resulting table with moduli_ocr table in this way:
SELECT
noleggio.*
FROM
(//query//) AS noleggio
LEFT JOIN
moduli_ocr ON moduli_ocr.id_noleggio = noleggio.id;
Where //query// is the code above.
The error I got (running the query in MySQL Workbench is:
Error Code: 1054. Unknown column 'noleggio.id' in 'on clause'
BTW I'm not sure if I have to use RIGHT or LEFT join but I will check this once the query is properly 'running'.
Best regards.
It seems that you assign idnoleggio alias to the field "id". Try joining on
moduli_ocr.id_noleggio = noleggio.idnoleggio;

How can I get the latest package for all packages in SQL?

I have two tables, packages (with id, name as attributes) and releases (with url, upload_time, downloaded_bytes as attributes). Every package can have arbitrary many releases. I want a list of all packages with their latest release.
Currently, I have the following working code:
sql = ("SELECT `packages`.`id`, `name` FROM `packages`")
cursor.execute(sql)
packages = cursor.fetchall()
for pkg in packages:
sql = ("SELECT `url` FROM `releases` "
"WHERE `package_id` = %s "
"AND `downloaded_bytes` = 0 "
"ORDER BY `upload_time` DESC LIMIT 1")
cursor.execute(sql, (pkg['id'], ))
url = cursor.fetchone()
if url is not None:
package_url = url['url']
package_analysis.main(pkg['name'], package_url)
logging.info("Package '%s' done.", pkg['name'])
However, I think this is an ugly solution as I execute a lot of queries where I should only execute one query.
Can I do this in one query? How would the query look like?
Please note: I only want one result for each package. That means, the package numpy should only give the result for url="https://pypi.python.org/packages/cp35/n/numpy/numpy-1.10.1-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl" (version 1.10.1) and not 99 results.
What I've tried
SELECT
`packages`.`id`,
`packages`.`name`,
`releases`.`url`,
`releases`.`upload_time`,
`releases`.`release_number`
FROM
`packages`
JOIN
`releases` ON `releases`.`package_id` = `packages`.`id`
GROUP BY
`packages`.`name`
ORDER BY
`releases`.`upload_time` DESC
But that gives a seemingly random value for upload_time (and also url).
You can try this query:
select p.id, p.name, r.url, r.upload_time, r.release_number from
(select p.id, max(r.release_number) release_number from packages p
join releases r on p.id = r.package_id
group by p.id) a
join packages p on p.id = a.id
join releases r on r.release_number = a.release_number
It assumes that release_number is sortable, if not possible you can use max upload time instead.
Based on this answer (thank you Emiswelt) for mentioning it:
SELECT
`packages`.`id`,
`packages`.`name`,
`o`.`url`,
`o`.`upload_time`,
`o`.`release_number`
FROM
`releases` o
LEFT JOIN
`releases` b ON `o`.`package_id` = `b`.`package_id`
AND `o`.`upload_time` < `b`.`upload_time`
JOIN
`packages` ON `packages`.`id` = o.package_id
WHERE
`b`.`upload_time` is NULL
AND `o`.`downloaded_bytes` = 0
ORDER BY
`packages`.`name`
LIMIT 10
The query finishes execution within a fraction of a second.

unknown class: Fixnum Rails MySQL query - inserting variable breaks my search

I had a query which was working just fine:
#schedule = Schedule.find(params[:id])
#schedule_tasks = ScheduleTask.select("s.*, t.*, t.*, d.*, st.*").from("schedule_tasks st").
joins("left join schedules s ON s.id = st.schedule_id").
joins("left join tasks t ON t.id = st.task_id").
joins("right join days d ON d.id = st.day_id").
order("d.number, t.name").
group_by{|d| d.number}
I had to refine my search to only schedule_tasks with a specific schedule_id, so I edited the second line to:
joins("left join schedules s ON s.id = st.schedule_id AND s.id = ?", #schedule.id).
This has cause the following error:
unknown class: Fixnum
The error goes away if I take out the group_by - but I need that, and I have tried hard coding in the number instead of #schedule.id and that does not work either, a google search does not reveal a lot of details on this error.
For anyone coming here from Google, I used plain string interpolation to fix this issue. This method is vulnerable to SQL Injection, so make sure you type check your variables before using them.
In this case I would do
#schedule_id = #schedule.id
.
.
.
joins("left join schedules s ON s.id = st.schedule_id AND s.id = #{#schedule_id}")
Rather than following learning_to_swim's answer, which as noted is at risk of SQL injection, couldn't you cast your #schedule_id to a string?
#tasks = ScheduleTask.joins("left join [...] s.id = ?", #schedule.id.to_s)

arel union and latest conversation from messages

I need a list of messages where each one is the most recent in the "conversation" between the current user and each other user.
The same query is described in this question
The code I have so far is:
t1 = Arel::Table.new(:messages, :as => 't1')
t2 = Arel::Table.new(:messages, :as => 't2')
convs1 = t1.
project(
t1[:receiver_user_id].as('other_user_id'),
t1[:receiver_user_id].as('receiver_user_id'),
t1[:sender_user_id].as('sender_user_id'),
t1[:created_at].as('created_at')
).
where(t1[:sender_user_id].eq(user.id))
convs2 = t2.project(
t2[:sender_user_id].as('other_user_id'),
t2[:receiver_user_id].as('receiver_user_id'),
t2[:sender_user_id].as('sender_user_id'),
t2[:created_at].as('created_at')
).
where(t2[:receiver_user_id].eq(user.id))
conv = convs1.union(convs2)
First off, I get an error:
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check \
the manual that corresponds to your MySQL server version for the right syntax to use near \
'UNION SELECT `t2`...
This works if I manually replace "UNION" with "UNION ALL" in the sql produced below.
conv.to_sql from the above code produces:
SELECT `t1`.`receiver_user_id` AS other_user_id,
`t1`.`receiver_user_id` AS receiver_user_id, `
t1`.`sender_user_id` AS sender_user_id,
`t1`.`created_at` AS created_at
FROM `messages` `t1`
WHERE `t1`.`sender_user_id` = 50
UNION
SELECT `t2`.`sender_user_id` AS other_user_id,
`t2`.`receiver_user_id` AS receiver_user_id,
`t2`.`sender_user_id` AS sender_user_id,
`t2`.`created_at` AS created_at
FROM `messages` `t2`
WHERE `t2`.`receiver_user_id` = 50
Any idea why there's a MySQL UNION error. Is it an arel bug?
Secondly, any help with completing the query would be much appreciated.
Update:
Using Arel::Nodes::Union.new works
I think this is more probably a mysql fault, this is a mySQL error text. Something similar is discussed in here, but not exactly this issue.
Try to migrate to another sql server, and check again, or if union all works then use this:
conv = convs1.union(convs2, :all)
Based on documentation.
The problem is actually the parentheses in the sql. It works if I run:
Message.find_by_sql conv.to_sql.delete('()')
which removes the leading "(" and trailing ")"
Weird.. I don't know how I would chain this to complete the query. (Arel::Nodes::Union doesn't have a group method). This is Rails 3.1.4
I had a similar problem and solved it as follows:
def last_messages
Message.find_by_sql("
SELECT messages.*,
(IF(recipient_id = #{id}, 0,1)) as outlast,
users.avatar_name,
users.name
FROM messages
INNER JOIN users
ON users.id=(IF(recipient_id = #{id}, sender_id,recipient_id))
WHERE messages.id IN
( SELECT max(id)
FROM messages
WHERE recipient_id = #{id} OR sender_id = #{id}
GROUP BY (IF(recipient_id = #{id}, sender_id, recipient_id))
)
ORDER BY messages.id DESC")
end
This is the code I used instead in the end
all_msgs = Message.where("messages.sender_user_id = ? OR messages.receiver_user_id = ?",
user.id, user.id)
msg_ids = all_msgs.select("sender_user_id, receiver_user_id, max(id) as max_id")
.group(:sender_user_id, :receiver_user_id).map { |m| m.max_id }
all_msgs = all_msgs.where(:id => msg_ids)