union query to combine fields - ms-access

I don;t know SQL, so I am hoping that someone can provide me the SQL to copy and paste in order to merge all of the different unit price fields into one field called "merged_unit_price". Please note that many of the unit price values are null, so I would prefer that the null values don't get merged.
Thank you very much in advance, Nathaniel
SELECT p.ID AS Part_ID,
p.UNIT_PRICE,
d.UNIT_PRICE_1,
d.UNIT_PRICE_2,
d.UNIT_PRICE_3
FROM tbl_local_SYSADM_PART AS p
LEFT JOIN SYSADM_DISCOUNT_PRICE AS d
ON p.ID = d.PART_ID;

First off in your query make sure to exclude the Null values from you dataset. Cant remember if Access SQL uses Null or Nothing, so try it one way and see if it errors out.
SELECT p.ID AS Part_ID, p.UNIT_PRICE, d.UNIT_PRICE_1, d.UNIT_PRICE_2, d.UNIT_PRICE_3
FROM tbl_local_SYSADM_PART AS p
LEFT JOIN SYSADM_DISCOUNT_PRICE AS d ON p.ID = d.PART_ID;
WHERE p.UNIT_PRICE <> Nothing OR p.UNIT_PRICE_1 <> NOTHING OR p.UNIT_PRICE_2 <> NOTHING OR p.UNIT_PRICE_3 <> Nothing
As well, i would suggest you learn more about SQL statements, in general and access, cause you have limited yourself to just 4 UNIT_PRICE's and will eventually have to increase your table field signature. If it were me, i would break this table into Join Table, so you can have multiple Part_ID's and multiple UNIT_PRICE's. Currently you are restricted with one Part_ID and figuratively just one UNIT_PRICE (counting the 4 price fields as 1 record).

Related

Getting count from joined table

Here's my problem: I need to get the amount of test cases and issues associated to a project that meet certain conditions (test cases that are successful, and issues that are flaws of the application), but for some reason the amount doesn't add up. I have 10 test cases in a project, of which 6 are successful; and 8 issues, of which only 4 are flaws. However, the respective results for COUNT each show 24, which makes no sense. I did notice, though, that 24 happens to be 6 times 4, but I don't see how the query would multiply them.
Anyway... Can someone help me find which part of my query is wrong? How can I get the correct result? Thanks in advance.
Here's the query:
SELECT
p.codigo_proyecto,
p.nombre,
IFNULL(COUNT(iep.id_incidencia_etapa_proyecto), 0) AS cantidad_defectos,
IFNULL(COUNT(tc.id_test_case), 0) AS test_cases_exitosos,
CASE IFNULL(COUNT(tc.id_test_case), 0) WHEN 0 THEN 'No aplica'
ELSE CONCAT((IFNULL(COUNT(tc.id_test_case), 0) / IFNULL(COUNT(tc.id_test_case), 0)) * 100, '%') END AS tasa_defectos
FROM proyecto p
INNER JOIN etapa_proyecto ep ON p.codigo_proyecto = ep.codigo_proyecto
INNER JOIN incidencia_etapa_proyecto iep ON ep.id_etapa_proyecto = iep.id_etapa_proyecto
INNER JOIN incidencia i ON iep.id_incidencia = i.id_incidencia
INNER JOIN test_case tc ON ep.id_etapa_proyecto = tc.id_etapa_proyecto
INNER JOIN etapa_proyecto ep_ultima ON ep_ultima.id_etapa_proyecto =
(SELECT ep_ultima2.id_etapa_proyecto FROM etapa_proyecto ep_ultima2
WHERE p.codigo_proyecto = ep_ultima2.codigo_proyecto ORDER BY ep_ultima2.fecha_termino_real DESC LIMIT 1)
WHERE p.esta_cerrado = 1
AND i.es_defecto = 1
AND tc.resultado = 'Exitoso'
AND ep_ultima.fecha_termino_real BETWEEN '2015-01-01' AND '2016-12-31';
I would have thought it obvious that you're not going to get the expected output from an aggregate query without a GROUP BY (which suggests you're not really in a position to evaluate any advice given here effectively).
You've not said how the states of your data are represented in the database - so I'm having to make a lot of guesses based on SQL which is clearly very wrong. And I don't speak spanish/portugese or whatever your native language is.
It looks like you are inferring that a defect exists if the primary key of the defects table is null. Primary keys cannot be null. The only way this would make any sort of sense (BTW it still won't give you the answer you're looking for) is to do a LEFT JOIN rather than an INNER JOIN.
But even then a simple COUNT() will consider null cases (no record in source table) as 1 record in the output set.
Then you've got the problem that you will have the product of defects and test cases in your output - consider the case where you have no defects, but 2 tests cases (1,2) - the result of an outer joiun will be:
defect test
------ ----
null 1
null 2
If you just count the rows, you'll get 2 defects in your output.
Taking a simpler schema, this demonstrates the 2 methods for getting the values - note that they have very different performance characteristics.
SELECT project.id
, dilv.defects
, (SELECT COUNT(*)
FROM test_cases) AS tests
FROM project
LEFT JOIN ( SELECT project_id, COUNT(*) AS defects
FROM defect_table
GROUP BY project_id) AS dilv
ON project.id=dilv.project_id

Slow MYSQL query after using inner join and sub query

I have spent hours trying to get my query to run faster so far it works on my database.
however it takes 43 seconds to return my result. basically two tables are joined and I need to only return the latest order_history_id for each order_id with an order_status of 12.
I have tried using table shortcuts ie T1 T2 etc but to keep it simple my sql query has the relevant tables names below any help greatly appreciated
SELECT oc_order.order_id, oc_order.firstname, oc_order.lastname
FROM oc_order
INNER JOIN oc_order_history ON oc_order.order_id = oc_order_history.order_id
AND oc_order_history.comment NOT LIKE ''
AND oc_order_history.order_status_id LIKE '12'
AND order_history_id = (SELECT max(order_history_id)
FROM oc_order_history i
WHERE i.order_id = oc_order.order_id)
INNER JOIN is little bit more resources eating as it adds another filtering condition, i.e. it is really a LEFT JOIN + WHERE {joining column} IS NOT NULL. Having indexes on columns taking part in joins and/or where clauses (especially string values that are searched with LIKE) will help to minimise the resources cost.
In Your query You are using LIKE in WHERE clause but completely wrong thus I can say You are misusing it. LIKE is used when You need to search for strings but You only know part of the string, e.g.
name LIKE 'Pet%'
will match all the rows with names like Pete, Peter, Petra, Petronela, Petriarca, Peter Pan, etc... If You want to search for exact value, compare with comparator signs =, <>, <=, >=, e.g.
name = 'Peter'
Now consider also this query:
SELECT o.order_id, o.firstname, o.lastname
FROM oc_order o
LEFT JOIN oc_order_history oh USING(order_id)
WHERE oh.order_status_id = 12
AND oh.order_history_id IN (
SELECT MAX(order_history_id)
FROM oc_order_history
GROUP BY order_history_id
)
Do not use LIKE if you do not want to search a text inside of a field.
Also the do not put the WHERE conditions into the JOIN conditions.
In addition, check that you have SQL Indexes in the fields that you are joining and filtering on.
Update: after taking a look at your tables, I realised that oc_order_history.comment is a Text column, so search on this column is going to be very slow. If you try to remove the condition (like I did) I am sure your query it will be much faster. If you have to query for the comment column, try to change it to a VARCHAR or put and index.
Also you should have indexes at least in oc_order_history(order_status_id) and in oc_order_history(order_id)
SELECT oc_order.order_id, oc_order.firstname, oc_order.lastname
FROM oc_order
INNER JOIN oc_order_history ON oc_order.order_id = oc_order_history.order_id
WHERE oc_order_history.order_status_id = 12
AND order_history_id = (SELECT MAX(order_history_id)
FROM oc_order_history i
WHERE i.order_id = oc_order.order_id)

mysql query finding results using joined status table that needs EXIST and NOT EXIST results

I have been looking around for ages for a solution to my problem.
I have something that works but i am not sure it is the most efficient way of doing things and can't find anyone trying to do this when googling around.
I have a table with customers and a table with statuses that that customer has had.
If I want to find results where a customer has had a status happen I have managed to get the required results using a join, but sometimes I want to be able to find clients where not only has a status been reached but also where a few other statuses haven't been.
Currently I am doing this with a NOT EXISTS Sub query but it seem a bit slow and thinking about it if I have to check after finding a result that matches the first status through all the results again to see if it doesn't match another it could explain the slowness.
for instance a client could have a status of invoiced and a status of paid.
If I wanted to see which clients have been invoiced thats fine, If I want to see which clients have been invoiced and paid thats fine, but if I wanted to see which clients have been invoiced but NOT paid thats where I start having to use a NOT EXIST subquery
Is there another more efficient way around this? or is this the best way to proceed but I need to sort out how mysql uses indxes with these tables to be more efficient?
I can provide more detail of the actual sql if that helps?
Thanks
Matt
If this is over multiple clients then the usual solution would be to have a subselect for the status per client and then use LEFT OUTER JOIN to connect this.
Something like
SELECT *
FROM Clients a
LEFT OUTER JOIN (SELECT ClientId, COUNT(*) FROM ClientsStatus WHERE Status IN (1,2) GROUP BY ClientId) b
ON a.ClientId = b.ClientId
WHERE b.ClientId IS NULL
This (very rough) example is to give you a list of clients who do not have a status of 1 or 2.
You should be able to expand this basic idea to cover the scenarios / data you are dealing with
Edited for below
I have had a play with your SQL. I think you can use a JOIN onto the subselect fairly easily, but this doesn't seem to be checking anything other than whether a claim has had a status of 3 or 95.
SELECT claims.ID, claims.vat_rate, claims.com_rate,
claims.offer_val, claims.claim_value, claims.claim_ppi_amount, claims.claim_amount, claims.approx_loan_val, claims.salutationsa, claims.first_namesa, claims.last_namesa,
clients.salutation, clients.first_name,clients.last_name, clients.phone, clients.phone2, clients.mobile, clients.dob,clients.postcode, clients.address1, clients.address2, clients.town, client_claim_status.person,clients.ID
AS client_id,claims.ID AS claim_id, claims.date_added AS status_date_added,client_claim_status.date_added AS last_client_claim_status_date_added,work_suppliers.name AS refname, financial_institution.name AS lendname, clients.date_added AS client_date_added,ppi_claim_type_2.claim_type AS ppi_claim_type_name
FROM claims
RIGHT JOIN clients ON claims.client_id = clients.ID
RIGHT JOIN client_claim_status
ON claims.ID = client_claim_status.claim_id
AND client_claim_status.deleted != 'yes'
AND ((client_claim_status.status_id IN (1, 170))
AND client_claim_status.date_added < '2012-12-02 00:00:00' )
LEFT OUTER JOIN (SELECT claim_id FROM client_claim_status WHERE status_id IN (3, 95 )) Sub1
ON claims.ID = Sub1.claim_id
LEFT JOIN financial_institution ON claims.claim_against = financial_institution.ID
LEFT JOIN work_suppliers ON clients.work_supplier_id = work_suppliers.ID
LEFT JOIN ppi_claim_type_2 ON claims.ppi_claim_type_id = ppi_claim_type_2.ID
WHERE claims.deleted != 'yes'
AND Sub1.claim_id IS NULL
ORDER BY last_client_claim_status_date_added DESC
I would suggest that you rearrange the code to remove the RIGHT OUTER JOINs though to be honest. Mixing left and right joins up tend to be very confusing.

Dependant SubQuery v Left Join

This query displays the correct result but when doing an EXPLAIN, it lists it as a "Dependant SubQuery" which I'm led to believe is bad?
SELECT Competition.CompetitionID, Competition.CompetitionName, Competition.CompetitionStartDate
FROM Competition
WHERE CompetitionID NOT
IN (
SELECT CompetitionID
FROM PicksPoints
WHERE UserID =1
)
I tried changing the query to this:
SELECT Competition.CompetitionID, Competition.CompetitionName, Competition.CompetitionStartDate
FROM Competition
LEFT JOIN PicksPoints ON Competition.CompetitionID = PicksPoints.CompetitionID
WHERE UserID =1
and PicksPoints.PicksPointsID is null
but it displays 0 rows. What is wrong with the above compared to the first query that actually does work?
The seconds query cannot produce rows: it claims:
WHERE UserID =1
and PicksPoints.PicksPointsID is null
But to clarify, I rewrite as follows:
WHERE PicksPoints.UserID =1
and PicksPoints.PicksPointsID is null
So, on one hand, you are asking for rows on PicksPoints where UserId = 1, but then again you expect the row to not exist in the first place. Can you see the fail?
External joins are so tricky at that! Usually you filter using columns from the "outer" table, for example Competition. But you do not wish to do so; you wish to filter on the left-joined table. Try and rewrite as follows:
SELECT Competition.CompetitionID, Competition.CompetitionName, Competition.CompetitionStartDate
FROM Competition
LEFT JOIN PicksPoints ON (Competition.CompetitionID = PicksPoints.CompetitionID AND UserID = 1)
WHERE
PicksPoints.PicksPointsID is null
For more on this, read this nice post.
But, as an additional note, performance-wise you're in some trouble, using either subquery or the left join.
With subquery you're in trouble because up to 5.6 (where some good work has been done), MySQL is very bad with optimizing inner queries, and your subquery is expected to execute multiple times.
With the LEFT JOIN you are in trouble since a LEFT JOIN dictates the order of join from left to right. Yet your filtering is on the right table, which means you will not be able to use an index for filtering the USerID = 1 condition (or you would, and lose the index for the join).
These are two different queries. The first query looks for competitions associated with user id 1 (via the PicksPoints table), which the second joins with those rows that are associated with user id 1 that in addition have a null PicksPointsID.
The second query is coming out empty because you are joining against a table called PicksPoints and you are looking for rows in the join result that have PicksPointsID as null. This can only happen if
The second table had a row with a null PickPointsID and a competition id that matched a competition id in the first table, or
All the columns in the second table's contribution to the join are null because there is a competition id in the first table that did not appear in the second.
Since PicksPointsID really sounds like a primary key, it's case 2 that is showing up. So all the columns from PickPointsID are null, your where clause (UserID=1 and PicksPoints.PicksPointsID is null) will always be false and your result will be empty.
A plain left join should work for you
select c.CompetitionID, c.CompetitionName, c.CompetitionStartDate
from Competition c
left join PicksPoints p
on (c.CompetitionID = p.CompetitionID)
where p.UserID <> 1
Replacing the final where with an and (making a complex join clause) might also work. I'll leave it to you to analyze the plans for each query. :)
I'm not personally convinced of the need for the is null test. The article linked to by Shlomi Noach is excellent and you may find some tips in there to help you with this.

mysql if/else scenario

Ok, here's a fun one. I have 2 tables: tbl_notes, tbl_notes_categories
Simply, the tbl_notes has a categoryid, and I correlate the 2 tables with that ID. So, nothing too complicated.
I force users to choose a category, from a dropdown input, and stop them from submitting if they don't select something.
However, I want to change this, primarily for learning JOINs and how far I can go with them.
Sooooooo, I am not going to force a user to select a category, and instead, I will default the categoryid to zero, in the tbl_notes. (most users will select a category, but this is for other instances)
In the query, I am locked to showing only the notes that have a categoryid that exists in the tbl_notes_categories table. But, I would like to have a condition if the categoryid is not recognized OR is equal to zero, then specify another String. Like "--Unassigned--", or "--Category does not exist--"
Here's my original query:
SELECT n.notesubject, c.categoryname
FROM `tbl_notes` n, `tbl_notes_categories` c
WHERE n.categoryid = c.categoryid
This will not let me see the notes without a categoryid, so I pulled this one:
SELECT n.notesubject, c.categoryname
FROM `tbl_notes` n
LEFT JOIN `tbl_notes_categories` c ON n.categoryid = c.categoryid
And that helps, but I'm stuck at the 'condition' of displaying alternate text, in the case of a missing category record from the categories table.
In MySQL you can use IFNULL:
SELECT
n.notesubject,
IFNULL(c.categoryname, 'Unknown') AS categoryname
FROM tbl_notes AS n
LEFT JOIN tbl_notes_categories AS c
ON n.categoryid = c.categoryid
This will work if the category is not found, but it will also work if the category id is zero assuming that you don't have a matching row in your category table because then it will also not be found. If for some reason you do want a row in the categroy table with id zero then you can just set its name to 'Unknown'.
Note that IFNULL is MySQL specific. The function COALESCE will also work and is supported by more databases.
For IF/ELSE statements in general in MySQL can use IF or for a more general solution use a CASE expression: CASE WHEN condition THEN expr1 ELSE expr2 END.