What I was trying to do is to get data from multiple tables, supposed that I have the following results in my query:
The numbers in the column ticket_item_type represents certain table. For example, 2 is for tbl_company and 3 is for tbl_lease. Then the details represents the id of a certain record in that table.
Suppose that I want to get the title of those records using ticket_item_type and details. Is it possible to embed it to the results? Or should I make separate queries for each.
I know JOIN, but I is it only for single table?
Here's my MYSQL query for the image above:
SELECT *
FROM
(SELECT *
FROM ticket_items
WHERE hs_customer = 1
AND ticket IN
(SELECT id
FROM tickets
WHERE hs_customer='1'
AND ticket_status = 'dispatch_reviewed')
AND ticket IN
(SELECT ticket
FROM ticket_items
WHERE ticket_item_type = 5
AND details = '159')) AS TB1
WHERE ticket_item_type IN (3,
2,
8)
You could try something like this:
SELECT
TB1.*,
CASE
WHEN TB1.ticket_item_type = 2 THEN t2.title
WHEN TB1.ticket_item_type = 3 THEN t3.title
WHEN TB1.ticket_item_type = 8 THEN t8.title
ELSE 'NA'
END as title
FROM
(
SELECT *
FROM ticket_items
WHERE hs_customer = 1
AND ticket IN (SELECT id FROM tickets WHERE hs_customer='1' AND ticket_status = 'dispatch_reviewed')
AND ticket IN (SELECT ticket FROM ticket_items WHERE ticket_item_type = 5 AND details = '159')
) AS TB1
LEFT JOIN tbl_company t2 ON TB1.details = t2.id
LEFT JOIN tbl_lease t3 ON TB1.details = t3.id
LEFT JOIN tbl_next t8 ON TB1.details = t8.id
WHERE ticket_item_type IN (3, 2, 8)
However, this is not a design that I would prefer. Without looking at details of your database it's going to be hard to write a query to cover multiple types of ticket_item_type. I hope this query works for you, though.
Related
I have two tables, tasks and views, with the following structure:
tasks
-- id
-- status
views
-- id
-- taskid (FK of tasks.id)
-- status
And the tasks table, has a row with id = 1 and status = 1, whilst the views table has two rows with id = 1, taskid = 1, status = 1 and id = 2, taskid = 1, status = 0.
When I try to get all the tasks id that have all its views status set to 1 and the task's status itself set to 1 too and only, then I get in return a row with task id = 1 because view number 1 is set to 1 and view number 2 is set to 0.
So basically, what I need is an SQL statement that returns only one row for each task that has all its views and task status set to 1 (tasks.status = 1, views.status = 1) and only when that happens, and if any of the tasks' views is set to something different than 1, then the SQL statement doesn't return it.
Here is my SQL Statement so far which kind of works, but there is still something I am missing because it doesn't work as expected. Sorry if something isn't clear!
SELECT tasks.id FROM tasks JOIN views ON tasks.id = views.taskid WHERE tasks.status = 1 AND views.status = 1;
Join tasks to a query that uses aggregation to return only the taskids with min status set to 1 (which means there is no 0):
SELECT t.id
FROM tasks t
INNER JOIN (
SELECT taskid
FROM views
GROUP BY taskid
HAVING MIN(status) = 1
) v ON v.taskid = t.id
WHERE t.status = 1;
with t as (select taskid,
count(status) status_cnt,
sum(case when status = 1 then 1 else 0 end) as status_1_cnt
from views
group by taskid),
t2 as (select taskid from t where status_1_cnt > 0 and status_cnt = status_1_cnt)
select tasks.id from tasks join t2 on tasks.id = t2.taskid and status = 1
so If I am reading your question correctly you want all of the statuses in the view to be 1 per taskid. so I would count the view statuses and compare that count to where the view status is 1. (the case statement).
then just join this to the task table where the task status is 1
(although I like #forpas answer better)
Conceptually you only want to join on the records in the views table where status = 1, so like this:
SELECT A.id
FROM
tasks A
INNER JOIN
(
SELECT
tasks.taskid
FROM
views
WHERE
view.status = 1
) B
ON A.id = B.taskid
Although the syntax is less intuitive, this is equivalent and shorter:
SELECT
tasks.id
FROM
tasks
JOIN views
ON tasks.id = views.taskid
AND view.status = 1
WHERE
tasks.status = 1
This should also work, for a different reason (more like a trick):
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON a.id = b.taskid
and a.status = b.status
WHERE
A.status = 1
This might be more stringent of a test if thats what you need (the matching records in views with the requirement that no other records with status = 0 exist in views) - but I would like to avoid this style of using a correlated subquery in real life if the tables are of an significant size:
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON A.id = B.taskid
WHERE
A.status = 1
AND B.status = 1
AND NOT EXISTS (SELECT * FROM views c
WHERE c.taskid = b.taskid and c.status = 0)
Finally this is a solution that thinks conceptually more in terms of the intersection of the sets:
SELECT A.id
FROM
tasks a
INNER JOIN views a
ON A.id = b.taskid
AND b.status = 1
LEFT JOIN views c
ON a.id = c.taskid
AND c.status = 0
WHERE
A.status = 1
AND c.status is null
I just saw that forpas has just shown a different but very good solution using aggregation with a min() clause to select only the appropriate records from views for use in joining to tasks which seems like it may be the winner to me :)
If I understand you correctly, you want to get id of task , if and ONLY if it's status = 1, and there are particular records in views table with ONLY same status = 1.
Then your query would be like this:
select tasks.id
from tasks
where status =1 and not exists(
select 1
from views
where taskid=tasks.id and views.status!=tasks.status)
Check demo https://www.db-fiddle.com/f/cQfQMx5LGJN516ND2iVj8y/3
Have 2 tables
User table with
user chat_id, kunnr (cust_code) & vkorg
Delivery table with
PO # and other delivery info, cust_code & sales_org
I want to verify if the user cust_code and sales_org match with shipmentdel's table
One user can belong to multiple sales org and a PO can have many delivery orders
Below is my working SQL statement, can this be simplified ?
SELECT * FROM ( SELECT a.* FROM ztelegram.ShipmentDel a
WHERE a.Cust_PO = 'WPO-01502') as t1
LEFT JOIN
( SELECT b.* FROM ztelegram.noti_setting b WHERE b.chat_id = '12345667' ) as t2
ON t1.sales_org = t2.vkorg AND t1.Sold_to_party_name = t2.kunnr
Without the need of t1 & t2, isnt the query working? Please check.
SELECT
*
FROM
ztelegram.ShipmentDel a
LEFT JOIN ztelegram.noti_setting b ON a.sales_org = b.vkorg AND a.Sold_to_party_name = b.kunnr
WHERE
a.Cust_PO = 'WPO-01502'
and b.chat_id = '12345667'
I'm trying to run a usage report. Basically there is a transaction log table that records every action taken against the database from the website.
i have three tables:
**organization:**
id
name
**people:**
id
organization_id
**transaction_log:**
id
people_id
table
action
Now, lets say I have 4 other tables that users create records in, those would look like this in the transaction_log:
{id: 1, people_id: 33, table: "tablea", action: "create"}
{id: 2, people_id: 44, table: "tableb", action: "create"}
What I want:
I want a result that looks something like this:
{organization_id: 1, name: "some org", tbla_count: 2000, tblb_count: 3000},
{organization_id: 2, name: "other org", tbla_count: 100, tblb_count:100}
Currently i've been doing this one query at a time (one for each table), but we have a lot more than 4 tables so it'd be nice if i could make it run all at once. Here is what I already have:
select
p.organization_id,
count(tl.action) as tbla_count
from
people p
LEFT JOIN
transaction_log tl ON p.id = tl.people_id AND tl.table = 'tablea' and tl.action = 'create'
GROUP BY
p.organization_id
ORDER BY
p.organization_id
When i try and add just another left join the numbers get way wrong. I did that by doing:
select
p.organization_id,
count(tl.action) as tbla_count
count(t2.action) as tblb_count
from
people p
LEFT JOIN
transaction_log tl ON p.id = tl.people_id AND tl.table = 'tablea' and tl.action = 'create'
LEFT JOIN
transaction_log t2 ON p.id = t2.people_id AND t2.table ='tableb' and t2.action = 'create
GROUP BY
p.organization_id
ORDER BY
p.organization_id
I believe it would work to first count the actions per person for each table in subqueries. Left join to each subquery result and summarize on total action count. I think your issue is that there could be many actions per people_id on each table.
select
p.organization_id,
sum(tl.action_count) as tbla_count
sum(t2.action_count) as tblb_count
from
people p
LEFT JOIN
(select people_id, count(action) as action_count
from transaction_log
where table = 'tablea' and action = 'create' group by people_id) tl
ON p.id = tl.people_id
LEFT JOIN
(select transaction_log people_id, count(action) as action_count
from transaction_log
where table = 'tableb' and action = 'create' group by people_id) t2
ON p.id = t2.people_id
GROUP BY
p.organization_id
ORDER BY
p.organization_id
I am building an AJAX like search page which allows a customer to select a number filters that will narrow down the search. For instance, a user has selected an 'iPhone 5' and has additional filters for capacity (32GB, 64GB) & colour (black, white..).
The user can only select a single radio box per category (so they could select 32GB & Black).. but they could not select (32GB & 64GB & black as two of these belong to the 'capacity' category).
I have added the schema here on sqlfiddle (please ignore the fact i've removed the primary keys they exist in the proper app they have just been removed along with some other fields/data to minimise the sqlfiddle)
http://sqlfiddle.com/#!2/964425
Can anyone suggest the best way to create the query to do the following:
Get all the prices for device_id '2939' (iPhone 5) which has the 'attributes' of '32GB' AND 'Black'
I currently have this - but this only works when selecting for a single attribute:
// search for device with '64GB' & 'Black' attributes (this currently doesn't return any rows)
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19'
AND `attribute_option_id` = '47';
// search for device with '64GB' attribute only (this currently DOES return a row)
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19';
Any advice on the database design would be appreciated too
Note: I was thinking to have a new column within the 'prices' table that has the matching attribute_ids serialised - would this be not good for optimisation however (e.g would it be slower than the current method)
Since attribute_option_id is an atomic value, it cannot have two different values for the same row. So your WHERE clause cannot match any record:
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19' # Here for one row, attribute_option_id is either 19
AND `attribute_option_id` = '47'; # of '47'. Cannot be the both
Instead of JOIN, you could try a subquery if you feel that is more readable. I think MySQL allow that syntax:
SELECT `prices`.*
FROM `prices`
WHERE `prices`.`device_id` = '2939'
AND EXISTS (SELECT *
FROM prices_attributes
WHERE price_id = `prices`.`id`
AND attribute_option_id IN ('19', '47') )
I don't know how MySQL will optimize the above solution. An alternative would be:
SELECT `prices`.*
FROM `prices`
WHERE `prices`.`id` IN (
SELECT DISTINCT `price_id`
FROM prices_attributes
WHERE attribute_option_id IN ('19', '47')
)
I think you should use the IN operator for the attribute_option_id and you set the values dynamically to the query; Also, using group_by you have only one row per price so in effect you get all the prices. Apart from this, the design is ok.
Here, I have made an example:
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
and `attribute_option_id` in ('19','47')
group by `prices`.`device_id`, `prices`.`price`;
Here, you can also add an order clause to order by price:
order by `prices`.`price` desc;
Another way to solve this would be to use a distinct on price, like this:
select distinct(prices.price)
from prices
where prices.device_id = 2939
and id in (select price_id from prices_attributes where attribute_option_id in (19,47));
Join against the devices_attributes_options table several times, once for each attribute the item must have
Something like this:-
SELECT *
FROM devices a
INNER JOIN prices b ON a.id = b.device_id
INNER JOIN prices_attributes c ON b.id = c.price_id
INNER JOIN devices_attributes_options d ON c.attribute_option_id = d.id AND d.attribute_value = '32GB'
INNER JOIN devices_attributes_options e ON c.attribute_option_id = e.id AND e.attribute_value = 'Black'
WHERE a.id = 2939
As to putting serialised details into a field, this is a really bad idea and would come back to bite you in the future!
SELECT * FROM prices WHERE device_id=2939 AND id IN (SELECT price_id FROM prices_attributes WHERE attribute_option_id IN (19,47));
Is it what you're looking for?
EDIT: sorry, didn't notice you're asking for query using joins
I have two tables:
t1
------------------
inv_ID
inv_memID
inv_projID
t2
------------------
is_ID
is_msgID
is_contID
I need to get all t2.is_contID into an array where
inv_projID = 5
t2.is_msgID = t1.inv_ID and
t1.inv_memID = 1
Seem pretty straight forward but I'm stuck... Tried this:
SELECT t2.is_contID
INNER JOIN t1 ON (t1.inv_ID = t2.is_msgID)
FROM t2
WHERE t1.inv_projID = 5
AND t1.inv_memID = 1
What am I missing?
FROM comes before JOIN.
SELECT t2.is_contID
FROM t2
INNER JOIN t1 ON (t1.inv_ID = t2.is_msgID)
WHERE t1.inv_projID = 5
AND t1.inv_memID = 1
SQL is very fussy about the order of the keywords.
The correct order is:
SELECT
FROM
JOIN
WHERE
HAVING
GROUP BY
ORDER
LIMIT <<-- MySQL only, other DB's user other keywords in other places.