Complex SQL query I can't figure out - mysql

I'm working on creating a report for the open source tool Validation Manager. I managed to pull out a report of all requirements covered after lots of work. I'm trying to make a report to list the ones not covered, but using not in gets the query into a never ending processing state.
Here's the DD diagram:
The involved tables are in the bottom right side of the diagram. Sample data can be obtained here. What would be the correct way to get uncovered requirements?
FYI: Uncovered requirements are those that doesn't have a related step and/or their children requirements are covered.
The main issue is that there are, in theory, infinite number of levels of requirement relationships and the SQL I have only works for 2 levels. Trying to figure out a way to look as deep as necessary.
As reference, see the query for the covered requirements below (which is the opposite of what I need):
select
c.covered, t.total
from
(SELECT DISTINCT
count(distinct unique_id) as covered
FROM
requirement
WHERE
requirement.id IN (select
requirement.id
from
`requirement` requirement
INNER JOIN `step_has_requirement` step_has_requirement ON requirement.`id` = step_has_requirement.`requirement_id`
INNER JOIN `step` step ON step_has_requirement.`step_id` = step.`id`
AND step.`test_case_id` = step_has_requirement.`step_test_case_id`
AND step.`test_case_test_id` = step_has_requirement.`step_test_case_test_id`
INNER JOIN `test_case` test_case ON step.`test_case_id` = test_case.`id`
AND test_case.`test_id` = step.`test_case_test_id`
INNER JOIN `test` test ON test_case.`test_id` = test.`id`
INNER JOIN `test_plan_has_test` test_plan_has_test ON test.`id` = test_plan_has_test.`test_id`
INNER JOIN `test_plan` test_plan ON test_plan_has_test.`test_plan_id` = test_plan.`id`
AND test_plan.`test_project_id` = test_plan_has_test.`test_plan_test_project_id`
INNER JOIN `test_project` test_project ON test_plan.`test_project_id` = test_project.`id`
INNER JOIN `requirement_status` requirement_status ON requirement.`requirement_status_id` = requirement_status.`id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_project_id` = requirement.`requirement_spec_node_requirement_spec_project_id`
AND requirement_spec_node.`requirement_spec_spec_level_id` = requirement.`requirement_spec_node_requirement_spec_spec_level_id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id}))
or requirement.id IN (select parent_requirement_id from requirement_has_requirement where parent_requirement_id = requirement.id
and requirement_id in (select
requirement.id
from
`requirement` requirement
INNER JOIN `step_has_requirement` step_has_requirement ON requirement.`id` = step_has_requirement.`requirement_id`
INNER JOIN `step` step ON step_has_requirement.`step_id` = step.`id`
AND step.`test_case_id` = step_has_requirement.`step_test_case_id`
AND step.`test_case_test_id` = step_has_requirement.`step_test_case_test_id`
INNER JOIN `test_case` test_case ON step.`test_case_id` = test_case.`id`
AND test_case.`test_id` = step.`test_case_test_id`
INNER JOIN `test` test ON test_case.`test_id` = test.`id`
INNER JOIN `test_plan_has_test` test_plan_has_test ON test.`id` = test_plan_has_test.`test_id`
INNER JOIN `test_plan` test_plan ON test_plan_has_test.`test_plan_id` = test_plan.`id`
AND test_plan.`test_project_id` = test_plan_has_test.`test_plan_test_project_id`
INNER JOIN `test_project` test_project ON test_plan.`test_project_id` = test_project.`id`
INNER JOIN `requirement_status` requirement_status ON requirement.`requirement_status_id` = requirement_status.`id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_project_id` = requirement.`requirement_spec_node_requirement_spec_project_id`
AND requirement_spec_node.`requirement_spec_spec_level_id` = requirement.`requirement_spec_node_requirement_spec_spec_level_id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id})))
order by unique_id) c,
(SELECT
count(distinct unique_id) AS total
FROM
`requirement_status` requirement_status
INNER JOIN `requirement` requirement ON requirement_status.`id` = requirement.`requirement_status_id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
INNER JOIN `spec_level` spec_level ON requirement_spec.`spec_level_id` = spec_level.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id})) t
Note: The SQL there is an example on how I managed to do the opposite, get the covered requirements. I would like to get the ones not covered. That SQl query is working properly.
What I am looking for is same for the parts which are not covered now(in the above)!

First thing's first
Your schema is your biggest enemy. I have attached an SQLFiddle with your step table. It is a very impressive table, but impressive isn't always workable in SQL. You would do very well to refactor your tables and make them normalized. There are very few cases where it makes sense to put multiple integers into one text file with commas separating them. If the only thing you are going to be putting in that column, ever, is integers separated by columns, you are failing to make your SQL schema even First Normal Form. While it may seem easier to design your schema this way, it is only on the face that you are doing so. In reality, you are creating a mess of epic proportions for yourself - as you may now be discovering. By failing to even meet First Normal Form, you are failing to take advantage of any of SQL's inherent relational power.
Edit This is a fairly large schema to take in. My reaction to being not 1NF was the text part of step. I don't really know what it is aiming to do so it is hard to say for sure, but it put up a big red flag when I saw multiple rows with the same integer columns in a text box separated by commas. That usually is a sign that several columns have been concatenated into one column. After examining other parts of the schema, it is clear that other parts are normalized. It doesn't appear to be an integral part of your schema, so, my mistake. That being said this is still a very complex application with a large number of cross referencing tables. Having both requirement_has_requirement and step_has_requirement as a table may have benefits but it also has serious drawbacks.
I question whether you need to differentiate steps from requirements in the way you currently are. Is a requirement not just another step? I understand you need different columns, but that could be solved by having a requirement_addendum and a step_addendum table, which can be called on at need and ignored at need as well. I note that you have versioning in requirement. Do you not anticipate that you will need versions in step? Do you anticipate that some of your requirements will be versioned at different times than others? Could a version table be created to cover the three version columns in order to have just one version_id in your requirement table and related tables?
In any case, assuming you can't do anything substantial to this table and you just need to pull a query...
My Suggestion
You have not actually defined what "as deep as necessary" is, so you need to determine what "as deep as necessary" means. If you have a formulaic way of discovering this, you can accomplish this relatively easily by creating a recursive procedure like #RandomSeed suggested. If you do not have a particularly formulaic way of determining what "as deep as necessary" is, are you going to determine by a client-defined number of levels? If so you can still rely on a stored procedure.
If you want to make these determinations on a more case-by-case basis, or if you suspect these requirements might change, you can also consider hard-coding the information into a MySQL table which stores metadata for your schema. This can allow you to determine how many steps by running an SQL SELECT query on this metadata table to receive your answer. You can easily assign each step or each scenario to have a number of recursions you want to accomplish. You would be able to use this information in a Stored Procedure.
If you can alter your table at all...
The benefit to altering your table even slightly is that you can create a terminal to step_has_requirement and requirement_has_requirement. Each record would then have a "yes" (1) or a "no" (0) to determine if there was a requirement involved. You could then run a query on any record which was a 1 or a 0 at your leisure.
requirement_has_requirement
id | status | major_version | mid_version | minor_version
.. | 0 | NULL | NULL | NULL
.. | 1 | .. | .. | ..
step_has_requirement
id | status | ...
Etc.
Query now becomes as simple as toggling between status 0 and status 1 to find your records. You can query all elements of your hierarchy at the same time.
Please note that this becomes much easier and contains less repetition if step and requirement are in one table with additional columns on separate tables based on whether it was a requirement or a step. There are no doubt drawbacks to this but there are also benefits. If you have the ability to make these changes prior to Volume 1 it could be beneficial.
Conclusion
You clearly have a very sophisticated application in development. Unfortunately the sophistication is outgrowing your schema. There is no "best" way to accomplish what you are looking for without making some minor changes to your schema. If changing your schema is not currently an option then I strongly advise you to make a quick hack so as not to waste more time and make a request to adapt the schema soon, before this becomes an even larger headache for you.

It's a mess, but I took a crack at it. By breaking it up into chunks with CTEs, you can troubleshoot smaller pieces.
;WITH
cteRequirement (id) AS
( SELECT distinct requirement.id
FROM requirement
INNER JOIN step_has_requirement
ON requirement.id = step_has_requirement.requirement_id
INNER JOIN step
ON step.id = step_has_requirement.step_id
AND step.test_case_id = step_has_requirement.step_test_case_id
AND step.test_case_test_id = step_has_requirement.step_test_case_test_id
INNER JOIN test_case
ON test_case.id = step.test_case_id
AND test_case.test_id = step.test_case_test_id
INNER JOIN test
ON test.id = test_case.test_id
INNER JOIN test_plan_has_test
ON test_plan_has_test.test_id = test.id
INNER JOIN test_plan
ON test_plan.id = test_plan_has_test.test_plan_id
AND test_plan.test_project_id = test_plan_has_test.test_plan_test_project_id
INNER JOIN test_project
ON test_project.id = test_plan.test_project_id
INNER JOIN requirement_status
ON requirement_status.id = requirement.requirement_status_id
INNER JOIN requirement_spec_node
ON requirement_spec_node.id = requirement.requirement_spec_node_id
AND requirement_spec_node.requirement_spec_project_id = requirement.requirement_spec_node_requirement_spec_project_id
AND requirement_spec_node.requirement_spec_spec_level_id = requirement.requirement_spec_node_requirement_spec_spec_level_id
AND requirement_spec_node.requirement_spec_id = requirement.requirement_spec_node_requirement_spec_id
INNER JOIN requirement_spec
ON requirement_spec.id = requirement_spec_node.requirement_spec_id
AND requirement_spec.project_id = requirement_spec_node.requirement_spec_project_id
AND requirement_spec.spec_level_id = requirement_spec_node.requirement_spec_spec_level_id
INNER JOIN project
ON project.id = requirement_spec.project_id
WHERE requirement_status.[status] = 'general.approved'
and (project.id = $P{target_project_id} or project.parent_project_id = $P{target_project_id})
),
cteParent (id) AS
( SELECT DISTINCT parent_requirement_id
FROM requirement_has_requirement
INNER JOIN cteRequirement
ON cteRequirement.id = requirement_has_requirement.requirement_id
WHERE parent_requirement_id = requirement.id
),
ListOfRequirementIDs (requirement_id) AS
( SELECT id FROM cteRequirement UNION
SELECT id FROM cteParents
),
ListOfUniqueIDs (unique_id) AS
( SELECT DISTINCT unique_id
FROM requirement_status
INNER JOIN requirement
ON requirement.requirement_status_id = requirement_status.id
INNER JOIN requirement_spec_node
ON requirement_spec_node.id = requirement.requirement_spec_node_id
AND requirement_spec_node.requirement_spec_id = requirement.requirement_spec_node_requirement_spec_id
INNER JOIN requirement_spec
ON requirement_spec_node.requirement_spec_id = requirement_spec.id
AND requirement_spec.spec_level_id = requirement_spec_node.requirement_spec_spec_level_id
AND requirement_spec.project_id = requirement_spec_node.requirement_spec_project_id
INNER JOIN project
ON project.id = requirement_spec.project_id
INNER JOIN spec_level
ON spec_level.id = requirement_spec.spec_level_id
WHERE requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id} or project.parent_project_id = $P{target_project_id})
)
SELECT 'Covered' AS [Type], COUNT(ListOfRequirementIDs.requirement_id) AS Cnt
FROM ListOfRequirementIDs
UNION ALL
SELECT 'Total' AS [Type], COUNT(ListOfUniqueIDs.unique_id) AS Cnt
FROM ListOfUniqueIDs

Related

Select from SQL database information with newest revisions

I coding web app for my client and have issue with selecting from database raports with newest revisions.
SELECT
raports.*,
r1.*,
users.*,
(SELECT COUNT(*) FROM changes WHERE changes.changes_raports_id = raports.raports_id) as changes,
(SELECT changes.changes_date FROM changes WHERE changes.changes_raports_id = raports.raports_id ORDER BY changes.changes_date DESC LIMIT 1) as last_change,
(SUM(injuries.injuries_min_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as min,
(SUM(injuries.injuries_max_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as max
FROM raports
LEFT JOIN users
ON users.users_id = raports.raports_users_id
LEFT JOIN changes
ON changes.changes_raports_id = raports.raports_id
LEFT JOIN raports_to_changes r1
ON r1.raports_to_changes_raports_id = raports.raports_id
LEFT JOIN injuries_to_raports
ON injuries_to_raports.injuries_to_raports_raports_id = r1.raports_to_changes_raports_id
LEFT JOIN injuries
ON injuries_to_raports.injuries_to_raports_injuries_id = injuries.injuries_id
WHERE r1.raports_to_changes_changes_id = (SELECT max(raports_to_changes_changes_id) FROM raports_to_changes r2 WHERE r2.raports_to_changes_raports_id = r1.raports_to_changes_raports_id)
GROUP BY raports.raports_id ORDER BY raports.raports_id ASC;
In columns max and min i have not correct average from injuries. When i checked it and count all injuries i had 36 when true number is 2 but i have 18 revisions. So is logic that i have looped COUNT with all revisions but i want only the newest
I try changing WHERE statements and more LEFT JOINs but nothing helped.
Could someone fixed that code?
Thank you in advanced
Based on the clues revealed by your queries, the data model may look like this:
The select list shows that you need:
users information of a reports_id
aggregated injuries_min_procent and injuries_max_procent at raports_id level. (see cte_raport_injuries)
number of changes of a raports_id (see cte_raport_changes)
the last change_date of a raports_id (see cte_raport_changes)
I'm not sure about the need for raports_of_changes based on information revealed in the question, so I'm going to ignore it for now.
with cte_raport_injuries as (
select r.raports_id,
sum(i.injuries_min_procent) / count(*) as injuries_min_procent,
sum(i.injuries_max_procent) / count(*) as injuries_max_procent
from raports r
join injuries_to_raports ir
on r.raports_id = ir.injuries_to_raports_raports_id
join injuries i
on ir.injuries_to_raports_injuries_id = i.injuries_id
group by r.raports_id),
cte_raport_changes as (
select r.raports_id,
count(c.changes_id) as changes,
max(c.changes_date) as last_change
from raports r
join changes c
on r.raports_id = c.changes_raports_id
group by r.raports_id)
select u.users_id,
r.raports_id,
ri.injuries_min_procent,
ri.injuries_max_procent,
rc.changes,
rc.last_change
from raports r
join users u
on r.raports_users_id = u.users_id
join cte_raport_injuries ri
on r.raports_id = ri.raports_id
join cte_raport_changes rc
on r.raports_id = rc.raports_id;
The result looks like this:
users_id|raports_id|injuries_min_procent|injuries_max_procent|changes|last_change|
--------+----------+--------------------+--------------------+-------+-----------+
1| 11| 15.0000| 25.0000| 2| 2022-12-02|
So my question for you is what's in reports_to_changes that you need and what's its relationship between others? For further involvement from the community, you may want to share the following information in text format:
DDLs of each tables (primary key, foreign key, column names & data types)
Some representable sample data and basic business rules
Expected output

MySQL Creat View with all data where date is max

I want to create a view which combines the data with the maximal date from the tables shown in the picture. These should be grouped by the profileID.
Database ERM
The profileIDs are linked to profile.userID.
I tried different approches in my code. The fort one slects the data where date is max, but the join doesn't work. Every profileID will be joined with the same data.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `b91788dd8d05b5`#`%`
SQL SECURITY DEFINER
VIEW fitchallengersql1.profileview AS
Select p.userID,
(SELECT
`bf`.`bodyFat`
FROM
(`fitchallengersql1`.`bodyfatprofile` `bf`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bf`.`profileID` = `p`.`userID`)
AND (`bf`.`date` = (SELECT
MAX(`fitchallengersql1`.`bodyfatprofile`.`date`)
FROM
`fitchallengersql1`.`bodyfatprofile`)))) AS `bodyFat`,
(SELECT
`bw`.`bodyweight`
FROM
(`fitchallengersql1`.`bodyweightprofile` `bw`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bw`.`profileID` = `p`.`userID`)
AND (`bw`.`date` = (SELECT
MAX(`fitchallengersql1`.`bodyweightprofile`.`date`)
FROM
`fitchallengersql1`.`bodyweightprofile`)))) AS `bodyWeight`,
(SELECT
`bmi`.`bmi`
FROM
(`fitchallengersql1`.`bmiprofile` `bmi`
JOIN `fitchallengersql1`.`profile` `p`)
WHERE
((`bmi`.`profileID` = `p`.`userID`)
AND (`bmi`.`date` = (SELECT
MAX(`fitchallengersql1`.`bmiprofile`.`date`)
FROM
`fitchallengersql1`.`bmiprofile`)))) AS `bmi`
From profile
In the second one the join works how it should, but I can't figure out a way to select just the data where date is max.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `b91788dd8d05b5`#`%`
SQL SECURITY DEFINER
VIEW `fitchallengersql1`.`profileview` AS
SELECT
`p`.`userID` AS `userID`,
`p`.`privacy` AS `privacy`,
`bs`.`size` AS `bodysize`,
`bw`.`bodyweight` AS `bodyweight`,
`bf`.`bodyFat` AS `bodyfat`,
`bmi`.`bmi` AS `bmi`
FROM
((((`fitchallengersql1`.`profile` `p`
JOIN `fitchallengersql1`.`bodysizeprofile` `bs`)
JOIN `fitchallengersql1`.`bodyweightprofile` `bw`)
JOIN `fitchallengersql1`.`bmiprofile` `bmi`)
JOIN `fitchallengersql1`.`bodyfatprofile` `bf`)
WHERE
((`p`.`userID` = `bs`.`profileID`)
AND (`p`.`userID` = `bw`.`profileID`)
AND (`p`.`userID` = `bmi`.`profileID`)
AND (`p`.`userID` = `bf`.`profileID`))
Hope someone could help me.
Thank you!
fleewe
Hope following query gives what you need. Please follow the pattern and join the rest of the tables. Please note that when the table grows these will definitely have performance issues as this require huge processing.
-- Select the columns that you need
select p.*, lbp.*
from profile p
inner join (
-- get the latest bmiprofile per user profile
select bp1.*
from bmiprofile bp1
inner join (select profileID, max(date) as date from bmiprofile group by profileID) as bp2 on bp1.prfileId = bp2.profileId and bp1.date = bp2.date
) as lbp on lbp.ProfileId = p.userId
-- Join the other tables in similar way
this is only a comment, but I needed formating capability:
Don't place the joining predicates into the where clause if using ANSI join syntax, instead use ON followed by the relevant predicates. e.g.
FROM `fitchallengersql1`.`profile` `p`
JOIN `fitchallengersql1`.`bodysizeprofile` `bs` ON `p`.`userID` = `bs`.`profileID`
JOIN `fitchallengersql1`.`bodyweightprofile` `bw` ON `p`.`userID` = `bw`.`profileID`
JOIN `fitchallengersql1`.`bmiprofile` `bmi` ON `p`.`userID` = `bmi`.`profileID`
JOIN `fitchallengersql1`.`bodyfatprofile` `bf` ON `p`.`userID` = `bf`.`profileID`

MySQL Database design advice - using joins

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

Ms Access query not working. Please suggest

Help needed for the below query. Thanks
SELECT b.SchemeCode_Db,
'DBELE',
1,
SecurityCode_Db,
"DIRECT",
Qty,
Price,
((Commission + TransferCharge) / Qty) AS Charges,
"",
iif(Buy_sell_code = "1110",
((Qty * Price) + Commission + TransferCharge),
iif(Buy_sell_code = "1120", ((Qty * Price) - Commission
- TransferCharge
))) AS totalCost,
BrokerCode_Db,
"",
Deal,
Format(Tradedate, "dd/MM/yyyy"),
Format(Valuedate, "dd/MM/yyyy"),
'', 'BSE', 'CH', 'D', '',
iif(Buy_sell_code = "1110",
'PUR',
iif(Buy_sell_code = "1120", 'SAL')) AS txn,
'USD' AS cur
FROM tbl_EQUITYINPUT a
LEFT JOIN tbl_EQUITYMapping b
ON FundCode = SchemeCode_Client
LEFT JOIN tbl_EQUITYMapping c
ON Ticker = SecurityCode_Client
LEFT JOIN tbl_EQUITYMapping d
ON Broker = Brokercode_Client
The Access db engine requires parentheses in the FROM clause when your query includes more than one JOIN. I suspect this FROM clause version will be a step closer to something the db engine will accept.
FROM
((tbl_EQUITYINPUT a
LEFT JOIN tbl_EQUITYMapping b
ON FundCode = SchemeCode_Client)
LEFT JOIN tbl_EQUITYMapping c
ON Ticker = SecurityCode_Client)
LEFT JOIN tbl_EQUITYMapping d
ON Broker = Brokercode_Client
However, I'm uncertain whether the db engine will be confused sorting out which join field comes from which table source. I would prefix those field names with the proper table alias.
But I think your most direct route to joy for this may be to start with a new query in Design View in the query designer. Add tbl_EQUITYINPUT and 3 copies of tbl_EQUITYMapping and assign the aliases. Then set up your joins between them while still in Design View. The query designer understands the join rules which keep the engine happy, so will guide you to the correct join syntax. And it will also include the aliases with the field names in your joins.
I'm wondering if it's confused over which instance of tbl_EQUITYMapping to join against.
I'd expect to see your from block look a little more like this:
select *
FROM tbl_EQUITYINPUT a
LEFT JOIN tbl_EQUITYMapping b
ON a.FundCode = b.SchemeCode_Client
LEFT JOIN tbl_EQUITYMapping c
ON a.Ticker = c.SecurityCode_Client
LEFT JOIN tbl_EQUITYMapping d
ON a.Broker = d.Brokercode_Client
In this case, you are joining three different copies of tbl_EQUITYMapping with tbl_EQUITYINPUT. But I don't think that is what you want to do. If you are pulling data from tbl_EQUITYMapping, the select won't know which copy to pull it from.
I expect that SchemeCode_Client, SecurityCode_Client, and Brokercode_Client form a composite key for tbl_EQUITYMapping. In which case I would expect a from block that looked like this.
select *
FROM tbl_EQUITYINPUT a
LEFT JOIN tbl_EQUITYMapping b
ON (a.FundCode = b.SchemeCode_Client
AND a.Ticker = b.SecurityCode_Client
AND a.Broker = B.Brokercode_Client)
In this case, you'd get only one copy of tbl_EQUITYMapping
You could equally well do something like this:
select *
from tbl_EQUITYINPUT a,
tbl_EQUITYMapping b
where
(a.FundCode = b.SchemeCode_Client
AND a.Ticker = b.SecurityCode_Client
AND a.Broker = B.Brokercode_Client)
(the designer may or may not optimise that for you in the former version)

Optimising a SQL Query where multiple left join duplicated twice

If someone could offer advice on improving the below query this would be most useful. I am unsure how I can make improvement when i have a left join twice in many instance to seperate tables. For example I have a location left join to the user table and a location left join to the image gallery table. I was unsure if i could optimise the sql from this point of view. It is very slow at the moment. I have ensured all columns are indexed on all joins and where statements.
SELECT im.alias_title, im.title,im.guid_id, im.description, im.hits, im.show_comment, im.can_print,
im.can_download, im.can_share, im.created_on, im.date_taken, im.approved, im.visible,
ad.address_line_1, ad.address_line_2, ad.town_village_city, ad.state_province_county, ad.postal_code, ad.other_address_detail, co.country,
geo.latitude, geo.longitude, geo.zoom, geo.yaw, geo.pitch,
c.make, c.model,
us.first_name, us.surname, uf.user_id, uf.real_name, uf.user_name, uf.gender, uf.description, uf.description, uf.buddy_icon_url, uf.first_taken_date, uf.first_date,
uf.time_zone_label, uf.time_zone_offset,
adf.address_line_1 as user_address_line_1, adf.address_line_2 as user_address_line_2, adf.town_village_city as user_town_village_city, adf.state_province_county as user_state_province_county,
adf.postal_code as user_postal_code, adf.other_address_detail as user_other_address_detail, cof.country as user_country,
geof.latitude as user_geolocation_latitude, geof.longitude as user_geolocation_longitude, geof.zoom as user_geolocation_zoom, geof.yaw as user_geolocation_yaw, geof.pitch as user_geolocation_pitch,
im.alias_title = in_image_alias_title AS image_selected -- image selected
FROM image im
LEFT JOIN address ad ON im.address_id = ad.id
LEFT JOIN country co ON ad.country_id = co.id
LEFT JOIN geolocation geo ON im.geolocation_id = geo.id
LEFT JOIN camera c ON im.camera_id = c.id
INNER JOIN user us ON im.user_id = us.id
LEFT JOIN user_flickr uf ON us.id = uf.id
LEFT JOIN address adf ON uf.address_id =adf.id
LEFT JOIN country cof ON ad.country_id = cof.id
LEFT JOIN geolocation geof ON uf.geolocation_id = geof.id
WHERE (im.alias_title = in_image_alias_title OR im.user_id = user_id)
AND im.approved = in_image_approved
AND im.visible = in_image_visible
AND (im.advertise_to <= NOW() OR im.advertise_to IS NULL)
ORDER BY image_selected DESC;
After the discussion / chat room, and learning more of what you were trying to do...
Build a compound index on the components associated with your where clause so all parts can be applied, not just the best of the first key element. Also, by removing the "alias_title" from the where clause (since you were getting the user ID based on the alias title to begin with), it was a redundant clause taking up more consideration in the query.
I would index on (user_id, approved, visible, advertise_to )
The results will come back and be small in the scheme of things, so your ultimate "order by" clause will have no problem with its final sort output.