Derived column results - sql

i'm an sql novice and have to Formulate an SQL query that lists all 5 columns from a QUALITY table and adds two more columns: ProductCode of the items produced in the batch, and a derived column BatchQuality that contains “Poor” if the batch is of poor quality (contains more than 1 defective item) and “Good” otherwise.
I'm pulling from 3 tables that I put in an oracle database: Production table(contains serialno, batchno, and productcode), Quality table (batchno, test1, test2, teste3, test4), and defective table (defectiveid, serialno).
I'm able to get 6 out of 7 columns by using the following:
select q.batchno, q.test1, q.test2, q.test3, q.test4, p.productcode_id
from production p, defective d, quality q
where d.serialno = p.serialno
and p.batchno = q.batchno;
Any ideas on how to get the last column called batchquality that says if it's good or poor? I'm thinking that I need a count function, but once I have that, how would I go about getting a new column that would state poor or good?
Appreciate any help that can be provided.

Your current query is an inner join using an old, outdated implicit join in the where clause. I assume the defective table only contains a row for a product if there was a defect. Your inner join will always return defective parts only, never parts without defects. For that you need an outer join. Another reason to ditch the outdated implicit joins and use an explicit JOIN operator:
select q.batchno, q.test1, q.test2, q.test3, q.test4, p.productcode_id
from production p
JOIN quality q ON p.batchno = q.batchno;
LEFT JOIN defective d ON d.serialno = p.serialno
For products that do not have defects, the values for the columns from the defective table will be null. So to get a flag if a product had is "good" or "bad" you need to check if the value is null:
select q.batchno, q.test1, q.test2, q.test3, q.test4, p.productcode_id,
case
when d.serialno is null then 'good'
else 'bad'
as batch_quality
from production p
JOIN quality q ON p.batchno = q.batchno;
LEFT JOIN defective d ON d.serialno = p.serialno
Due to the nature of joins, the above statement will however repeat each row from the production table for each row in the quality and defective table. It is not clear to me if you want that or not.

Related

Retrieve data from multiple tables returning null and not null values

I'm trying to create a query which needs to retrieve the latest prices for thousands of items; the thing is, I need two separate columns from two tables, to return null or not null values.
These two tables contain prices which are different from one another.
If I don't have a price in column A from table 1, it should return null, and column B from table 2 would return a value (if there's data).
I'm leaving below the latest "version" of the query I tried to run but again, to no avail; the data is incorrect, it returns the wrong prices.
SELECT a.orderid,
a.itemid,
d.currency,
d.itemcategory,
a.originalprice,
c.companyid,
b.price1,
e.price2,
Max(b.date) AS date,
c.companycategory
FROM orders AS a
INNER JOIN companydata AS b
ON a.itemid = b.itemid
INNER JOIN companycodes AS c
ON a.orderid = c.orderid
INNER JOIN orderoverview AS d
ON a.orderid = d.orderid
INNER JOIN pricingdata AS e
ON a.sku = e.sku
WHERE a.orderid = '123456'
GROUP BY a.orderid,
a.itemid,
d.currency,
d.itemcategory,
a.originalprice,
c.companyid,
b.price1,
e.price2,
c.companycategory
It doesn't even return the latest pricing data for an item.
I am not sure if I should've used different types of joins but I spent the entire day googling and trying stuff.
The tables containing the prices are pricingdata (e) and companydata (b); if there are no prices for the companies the orders were created, they should return null values.
So far this query returned horrific results, and I tried using CASE but it won't work for checking multiple items at once; I will search for these prices by the orderid which may contain thousands of items.
Temps were my first attempt then I started questioning if I really need them so I gave up.
I also tried using while loops but...failed miserably x2.
I read about cursors but I don't think they apply here.
If it wasn't obvious by my first world problems, I'm a beginner.
Any help is highly appreciated and I thank you all in advance!
L.E. tried Dale's K advice and managed to enter the data here SQL Fidler test
By "incorrect prices" I mean it ignores the max(date) and somehow brings prices from other items/companies.
The output should bring the latest price per item, company and supplier. If there's data missing for the company/supplier, the cell should be populated with NULL.
Thank you once more!

Joining 3 tables in Sqlite and not receiving expected output

I understand similar question have been posted, however my issue isn't an error rather the lack of the desired result. I'm trying to join 3 tables each with 10,000 observations and combine them in the one table, however when i use inner join the observations reduce to little over 4000. I understand that INNER JOIN is essentially an intersection but I'm expecting 10,000 observations and based on my code I don't see how that is occurring. Here is my code:
SELECT *
FROM Characteristics
INNER JOIN Prices ON Prices.pid = Characteristics.pid
INNER JOIN Locations ON Locations.tid = Characteristics.tid
;
CHARACTERISTICS
||Property_Id|| ||Beds|| ||Baths|| ||Type_ID||
PRICES
||Price|| ||Year|| ||Property_ID||
LOCATIONS
||Type_ID|| ||X coord|| ||Y coord||
Those are representative of the tables I didn't include numbers because of formatting issues but as you can imagine the number contained in Property_id and Type_id are the same for all columns regardless of table, what i would like is one table with each of the respective columns containing 10,000 rows, i've checked for NA values on R and they're all of the same length.
If you want to keep all characteristics -- even when there are no matches in the other tables -- then use left join:
SELECT *
FROM Characteristics c LEFT JOIN
Prices p
ON p.pid = c.pid LEFT JOIN
Locations l
ON l.tid = c.tid;

How to join 4 tables in SQL?

I just started using SQL and I need some help. I have 4 tables in a database. All four are connected with each other. I need to find the amount of unique transactions but can't seem to find it.
Transactions
transaction_id pk
name
Partyinvolved
transaction.id pk
partyinvolved.id
type (buyer, seller)
PartyCompany
partyinvolved.id
Partycompany.id
Companies
PartyCompany.id pk
sector
pk = primary key
The transaction is unique if the conditions are met.
I only need a certain sector out of Companies, this is condition1. Condition2 is a condition inside table Partyinvolved but we first need to execute condition1. I know the conditions but do not know where to put them.
SELECT *
FROM group
INNER JOIN groupB ON groupB.group_id = group.id
INNER JOIN companies ON companies.id = groupB.company_id
WHERE condition1 AND condition2 ;
I want to output the amount of unique transactions with the name.
It is a bit unclear what you are asking as your table definitions look like your hinting at column meanings more than names such as partycompany.id you are probably meaning the column that stores the relationship to PartyCompany column Id......
Anyway, If I follow that logic and I look at your questions about wanting to know where to limit the recordsets during the join. You could do it in Where clause because you are using an Inner Join and it wont mess you your results, but the same would not be true if you were to use an outer join. Plus for optimization it is typically best to add the limiter to the ON condition of the join.
I am also a bit lost as to what exactly you want e.g. a count of transactions or the actual transactions associated with a particular sector for instance. Anyway, either should be able to be derived from a basic query structure like:
SELECT
t.*
FROM
Companies co
INNER JOIN PartyCompancy pco
ON co.PartyCompanyId = pco.PartyCompanyId
INNER JOIN PartyInvolved pinv
ON pco.PartyInvolvedId = pinv.PartyInvolvedId
AND pinv.[type] = 'buyer'
INNER JOIN Transactions t
ON ping.TransactionId = t.TransactionId
WHERE
co.sector = 'some sector'

Some SQL Questions

I have been using SQL for years, but have mostly been using the query designer within SQL Studio (etc.) to put together my queries. I've recently found some time to actually "learn" what everything is doing and have set myself the following fairly simple tasks. Before I begin, I'd like to ask the SOF community their thoughts on the questions, possible answers and any tips they may have.
The questions are;
Find all records w/ a duplicate in a particular column (e.g. a linking id is in more than 1 record throughout table)
SUM price from a linked table within the same query (select within a select?)
Explain the difference between the 4 joins; LEFT, RIGHT, OUTER, INNER
Copy data from one table to another based on SELECT and WHERE criteria
Input welcomed & appreciated.
Chris
I recommend that you start by following some tutorials on this topic. Your questions are not uncommon questions for someone moving from a beginner to intermediate level in SQL. SQLZoo is an excellent resource for learning SQL so consider following that.
In response to your questions:
1) Find all records with a duplicate in a particular column
There are two steps here: find duplicate records and select those records. To find the duplicate records you should be doing something along the lines of:
select possible_duplicate_field, count(*)
from table
group by possible_duplicate_field
having count(*) > 1
What we're doing here is selecting everything from a table, then grouping it by the field we want to check for duplicates. The count function then gives me a count of the number of items within that group. The HAVING clause indicates that we want to filter AFTER the grouping to only show the groups which have more than one entry.
This is all fine in itself but it doesn't give you the actual records that have those values on them. If you knew the duplicate values then you'd write this:
select * from table where possible_duplicate_field = 'known_duplicate_value'
We can use the SELECT within a select to get a list of the matches:
select *
from table
where possible_duplicate_field in (
select possible_duplicate_field
from table
group by possible_duplicate_field
having count(*) > 1
)
2) SUM price from a linked table within the same query
This is a simple JOIN between two tables with a SUM of the two:
select sum(tableA.X + tableB.Y)
from tableA
join tableB on tableA.keyA = tableB.keyB
What you're doing here is joining two tables together where those two tables are linked by a key field. In this case, this is a natural join which operates as you would expect (i.e. get me everything from the left table which has a matching record in the right table).
3) Explain the difference between the 4 joins; LEFT, RIGHT, OUTER, INNER
Consider two tables A and B. The concept of "LEFT" and "RIGHT" in this case are slightly clearer if you read your SQL from left to right. So, when I say:
select x from A join B ...
The left table is "A" and the right table is "B". Now, when you explicitly say "LEFT" the SQL statement you are declaring which of the two tables you are joining is the primary table. What I mean by this is: Which table do I scan through first? Incidentally, if you omit the LEFT or RIGHT, then SQL implicitly uses LEFT.
For INNER and OUTER you are declaring what to do when matches don't exist in one of the tables. INNER declares that you want everything in the primary table (as declared using LEFT or RIGHT) where there is a matching record in the secondary table. Hence, if the primary table contains keys "X", "Y" and "Z", and the secondary table contains keys "X" and "Z", then an INNER will only return "X" and "Z" records from the two tables.
When OUTER is used, we're saying: Give me everything from the primary table and anything that matches from the secondary table. Hence, in the previous example, we'd get "X", "Y" and "Z" records in the output record set. However, there would be NULLs in the fields which should have come from the secondary table for key value "Y" as it doesn't exist in the secondary table.
4) Copy data from one table to another based on SELECT and WHERE criteria
This is pretty trivial and I'm surprised you've never encountered it. It's a simple nested SELECT in an INSERT statement (this may not be supported by your database - if not, try the next option):
insert into new_table select * from old_table where x = y
This assumes the tables have the same structure. If you have different structures then you'll need to specify the columns:
insert into new_table (list, of, fields)
select list, of, fields from old_table where x = y
Let's say you have 2 tables named :
[OrderLine] with the columns [Id, OrderId, ProductId, Qty, Status]
[Product] with [Id, Name, Price]
1) all orderline of command having more than 1 line (it's technically the same as looking for duplicates on OrderId :) :
select OrderId, count(*)
from OrderLine
group by OrderId
having count(*) > 1
2) total price for all order line of the order 1000
select sum(p.Price * ol.Qty) as Price
from OrderLine ol
inner join Product p on ol.ProductId = p.Id
where ol.OrderId = 1000
3) difference between joins:
a inner join b => take all a that has a match with b. if b is not found, a will be not be returned
a left join b => take all a, match them with b, include a even if b is not found
a righ join b => b left join a
a outer join b => (a left join b) union ( a right join b)
4) copy order lines to a history table :
insert into OrderLinesHistory
(CopiedOn, OrderLineId, OrderId, ProductId, Qty)
select
getDate(), Id, OrderId, ProductId, Qty
from
OrderLine
where
status = 'Closed'
To answer #4 and to perhaps show at least some understanding of SQL and the fact this isn't HW, just me trying to learn best practise;
SET NOCOUNT ON;
DECLARE #rc int
if #what = 1
BEGIN
select id from color_mapper where product = #productid and color = #colorid;
select #rc = ##rowcount
if #rc = 0
BEGIN
exec doSavingSPROC #colorid, #productid;
END
END
END

Select based on the number of appearances of an id in another table

I have a table B with cids and cities. I also have a table C that has these cids with extra information. I want to list all the cids in table C that are associated with ALL appearances of a given city in Table B.
My current solution relies on counting the number of times the given city appears in Table B and selecting only the cids that appear that many times. I don't know all the SQL syntax yet, but is there a way to select for this kind of pattern?
My current solution:
SELECT Agents.aid
FROM Agents, Customers, Orders
WHERE (Customers.city='Duluth')
AND (Agents.aid = Orders.aid)
AND (Customers.cid = Orders.cid)
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
It only works because I know right now with the HAVING statement.
Thanks for the help. I wasn't sure how to google this problem, since it's pretty specific.
EDIT: I'm pinpointing my problem a bit. I need to know how to determine if EVERY row in a table has a certain value for a field. Declaring a variable and counting the rows in a sub-selection and filtering out my results by IDs that appear that many times works, but It's really ugly.
There HAS to be a way to do this without explicitly count()ing rows. I hope.
Not an answer to your question, but a general improvement.
I'd recommend using JOIN syntax to join your tables together.
This would change your query to be:
SELECT Agents.aid
FROM Agents
INNER JOIN Orders
ON Agents.aid = Orders.aid
INNER JOIN Customers
ON Customers.cid = Orders.cid
WHERE Customers.city='Duluth'
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
What variant of SQL are you using?
To start with, you can (and should) use JOIN instead of doing it in the WHERE clause, e.g.,
select Agents.aid
from Agents
join Orders on Agents.aid = Orders.aid
join Customers on Customers.cid = Orders.cid
where Customers.city = 'Duluth'
group by Agents.aid
having count(Agents.aid) > 1
After that, I'm afraid I might be a little lost. Using the table names in your example query, what (in English, not pseudocode) are you trying to retrieve? For example, I think your sample query is retrieving the PK for all Agents that have been involved in at least 2 Orders involving Customers in Duluth.
Also, some table definitions for Agents, Orders, and Customers might help (then again, they might be irrelevant).
I'm not sure if I understood you problem, but I think the following query is what you want:
SELECT *
FROM customers b
INNER JOIN orders c USING (cid)
WHERE b.city = 'Duluth'
AND NOT EXISTS (SELECT 1
FROM customers b2
WHERE b2.city = b.city
AND b2.cid <> cid);
Probably you will need some indexes on these columns.