Getting repeats of output, possibly doing a join wrong? - sql

I'm having an issue where I'm getting some incorrect values in my output. I am binding the below highlighted table column with the circled column down the bottom. The service_id on the highlighted column is what is unique, but I need to bind the booking_id to retrieve the info (if that makes sense. What I end up getting is the top table where I get repeats, or the price is wrong. I should be getting only 5 lines in the top table.
Here's my code. I suspect I might be doing the join wrong?
SELECT bad.agent as Agents,
dog.SUPPLIER as SUPPLIER,
bad.status as TheStatus,
country.analysis_master1 as Country,
ftb.booking_actual_retail as BookingActualRetail,
ftb.Booking_Actual_Cost as BookingCost,
ftb.Booking_Actual_Retail_inc as BookingRetailINC,
fts.Service_Id,
fts.Service_Actual_Retail_inc as ServiceActualCostInc,
Product.SERVICE,
Product.SL_STATUS as SLSTATUS,
cat.name as Product2,
bad.LAST_SERVICE_DATE as Servicedate,
bad.LW_DATE as LWDATE,
ftb.Entered_Date as DATEENTERED,
ftb.Booking_Pax as PEOPLE,
ftb.Booking_Children as KIDS,
bad.TRAVELDATE as TRAVELDATE,
bad.FULL_REFERENCE
from BHD bad
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
inner join FTS on FTB.Booking_Id = fts.Booking_Id
inner join DRM Country on bad.agent = country.code
inner join BSL Product on bad.BHD_ID = Product.BHD_ID
inner join SRV cat on Product.SERVICE = cat.CODE
inner join OPT dog on Product.OPT_ID = dog.OPT_ID
where bad.STATUS = 'IV' AND bad.FULL_REFERENCE = 'LTIT129488'
UPDATE:
Ok, so it looks like this join here causes the multiple outputs:
inner join FTS on FTB.Booking_Id = fts.Booking_Id
I have included the two tables, their headers, and sample data

You have somewhere put the join for the service or supplier in the wrong way.. Please check this line again.
inner join SRV cat on Product.SERVICE = cat.CODE
UPDATED SOLUTION :
As per your updated screenshots, I found the issue...
you have joined like this.
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
In this join, your one table has single record against booking reference while another have multiple records against booking refrence. Thats why you are getting the multiple records in the output.
Remove this join and your problem will be solved. If you really want the data from this table then you can select in other way like using outer apply etc.

Related

Sub Queries, Group By's, and Joins

I am new to sql and am trying to complete an assignment for a class where were practicing using subqueries and joins.
The question I'm struggling with is: Provide a list of the airport city names and the travelers (last name) who have traveled to each airport via a flight.
Here are the tables in the database:Database Tables
Here is what I have so far:
SELECT Airport.CityName
FROM AIRPORT
GROUP BY AirportID
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID
SELECT TravLastName
FROM TRAVELER
but I'm getting an error on the first "Inner" and I know I'm probably nowhere close to being right. Any help would be appreciated.
The joins look fine but there should only be one select at the beginning and the group by should come at the end
SELECT
Airport.CityName,
TRAVELER.TravLastName
FROM AIRPORT
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID
GROUP BY
Airport.CityName,
TRAVELER.TravLastName;
Or, as we are not using any aggregate functions we can use DISTINCT. It is simpler and can run quicker.
SELECT DISTINCT
Airport.CityName,
TRAVELER.TravLastName
FROM AIRPORT
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID;
You don't want GROUP BY, you want DISTINCT:
SELECT DISTINCT
AIRPORT.CityName,
TRAVELER.TravLastName
FROM AIRPORT
JOIN FLIGHT ON FLIGHT.AirportID = AIRPORT.AirportID
JOIN TRAVELER ON TRAVELER.TravelerID = FLIGHT.TravelerID
Some tidy ups:
INNER is the default join type, so you can leave it out
DISTINCT means remove duplicates
FROM starts the list of tables to be joined. You can't add tables to the query in other places
A further tidy up would be to use table aliases, which rename the table in the context of the query - often using just the first letter of the table, to make the query smaller overall:
SELECT DISTINCT
a.CityName,
t.TravLastName
FROM AIRPORT a
JOIN FLIGHT f ON f.AirportID = a.AirportID
JOIN TRAVELER t ON t.TravelerID = f.TravelerID
The keyword AS may optionally be put between a table and its alias, eg FROM AIRPORT AS a.

On an SQL Select, how do i avoid getting 0 results if I want to query for optional data in another table?

I have a table with Customers which includes their contact person in the helpdesk. I have another table that lists all vacancies of the helpdesk employees - if they are currently sick or on vacation etc.
I need to get the helpdesk contact and the start/end time of their vacation IF there is an entry.
I currently have this (simplified):
SELECT *
FROM dbo.Customers, dbo.Projects, dbo.Vacations
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
AND dbo.Projects.HDContactID = dbo.Vacations.HDContactID
So if there is a vacation listed in the Vacations table, it works fine, but if there is no vacation at all, this will not return anything - what i want is that if there is no vacation, it simply returns the other data, and ignores the missing data (returns NULL, doesn't return anything, not important)
In any case, I need to get the Customers and Project data, even if the query can't find an entry in the Vacations table. How would I do this? I pretty new to SQL and couldn't find a similar question on this site
EDIT: I'm using SQL Server, currently using HeidiSQL
Try below query:
SELECT * FROM dbo.Customers, dbo.Projects
left join dbo.Vacations on dbo.Projects.HDContactID = dbo.Vacations.HDContactID
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
Use left join as mentioned by #Flying Thunder,
Example of the left join:
SELECT country.country_name_eng, city.city_name, customer.customer_name
FROM customer
LEFT JOIN city ON customer.city_id = city.id
LEFT JOIN country ON city.country_id = country.id;
You can find a nice guide for the joins and SQL here:
https://www.sqlshack.com/learn-sql-join-multiple-tables/
You should be using LEFT JOIN. In fact, you should never be using commas in the FROM clause. That is just archaic syntax and closes the powerful world of JOINs from your queries.
I also recommend using table aliases that are abbreviations of table names. The best are abbreviations for the table names:
SELECT *
FROM dbo.Customers c LEFT JOIN
dbo.Projects p
ON c.CustomerID = p.CustomerID LEFT JOIN
dbo.Vacations v
ON p.HDContactID = v.HDContactID
WHERE c.Phone = $Phone;
Have you try this to skip vacation record if not present like this:
SELECT * FROM dbo.Customers, dbo.Projects, dbo.Vacations
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
AND (dbo.Vacations.HDContactID IS NULL OR dbo.Projects.HDContactID = dbo.Vacations.HDContactID)

SQL multiple table Syntax

I have a table with a bunch of specific details and some detail codes for bridges. There are other separate tables with the descriptions for the various codes. For instance a table for Curb type, table for sidewalk type, another for joint type and so on.
I would like to create a query that gives me all the details per Bridge, but with the Code descriptions from the other tables for the fields that supply the code. the result would give me the ID, dimensions, curb code description, Sidewalk code description and so on.
Any help to point me in the right direction is sincerely appreciated.
Something like
SELECT b.Id, b.something, b.CurbTypeID, c.CurbDescription, b.SidewalkTypeID, s.SidewalkDescription
FROM Bridges b
INNER JOIN Curb c on c.CurbID = b.CurbTypeId
LEFT OUTER JOIN Sidewalk s on s.SidewalkID = b.SidewalkTypeID
The difference between INNER JOIN and LEFT OUTER JOIN being that you use a LEFT OUTER JOIN if you're not confident that all your SidewalkTypeID values are actually listed in the Sidewalk table, or if SidewalkTypeID is blank sometimes.

SQL Server : join tables causes the data to duplicate on every row

I have this query which is returning some redundant data. Can somebody please help me to correct this query. I have also attached the table relationship.
SELECT
dbo.supplierOrder.sectionID,
dbo.supplierOrder.supplierID,
dbo.supplierOrder.supplierOrderNo,
dbo.supplierOrder.supplierOrderCreated,
dbo.supplierOrder.supplierOrderConfirmStatus,
dbo.supplierOrderDetails.productID,
dbo.supplierOrderDetails.orderQty,
dbo.supplierOrderReceive.invoiceno,
dbo.supplierOrderReceive.supplierInvoiceno,
dbo.supplierOrderReceive.ID,
dbo.supplierOrderReceiveDetail.qtyArrived
FROM
dbo.supplierOrder
INNER JOIN
dbo.supplierOrderDetails ON (dbo.supplierOrderDetails.supplierOrderID = dbo.supplierOrder.ID)
INNER JOIN
dbo.supplierOrderReceive ON (dbo.supplierOrderReceive.supplierOrderID = dbo.supplierOrder.ID)
INNER JOIN
dbo.supplierOrderReceiveDetail ON (dbo.supplierOrderReceiveDetail.supplierOrderReceiveID = dbo.supplierOrderReceive.ID)
WHERE
dbo.supplierOrder.ID = 1 ;
here is the output that I get
which is not exactly what I was want. the last column qtyArrived should show only its related qty but here as you can see it is repeating for each of the productID
and here is the db tables and relationship
I think the last table should be join using also ProductId not only OrderID :
LEFT JOIN
dbo.supplierOrderReceiveDetail
ON
(dbo.supplierOrderReceiveDetail.supplierOrderReceiveID=dbo.supplierOrderReceive.ID)
AND
(dbo.supplierOrderReceiveDetail.ProductID =dbo.sdbo.supplierOrderDetails.ProductID)

Sql tables need help please

I'm trying to build a sql query which worked for the previous one which had 2 tables and it was pretty straight forward. This one though, has been driving me insane for 6 hours now.
The problem I have is that the results are only displayed should ALL criteria match and I don't want that. I would like the field to result back blank if it does not have an entry in the database.
I have a table and I want to display the orderrefno. At this point I want to check to see if a delivery note has been created and if so, I want to then see if an invoice has been created. Then report back to the report with the numbers of each but if they don't exist, the. It should just have the order no and the others would be both blank or just the invoice would be blank, should a delivery note been done.
I've tried building a query in crystal using inner, left join, right join, full but if an invoice does NOT exist I want it to list the delivery no and order no, but it won't.
I can do this in datasources and master sources in delphi and v studio, but would like to do a sql because the other easy is slow.
My tables are
Project
Order
Calloff
Calltodeliverylink
Delivery
Deliverytoinvoicelink
Invoice
Tables are linked as follows.
Project.id is the main point of entry.
Then
Order.projectid -- project.id
Calloff.orderid -- order.id
Callofftodeliverylink.deliveryid -- call off.id
Delivery.id -- callofftodeliverylink.deliveryid
Deliverytoinvoicelink.deliveryid -- delivery.id
Invoice.id -- deliverytoinvoicelink.invoiceid
Many many thanks
EDIT:
Added Code. Sorry for FROM section being a mess. In crystal drew the linking fields and asked it to show me the query and this is what it gave me.
SELECT
"Projects"."ID", "Orders"."IntOrderNo", "Deliveries"."DeliveryNo", "Projects"."InternalRef",
"CallOffs"."ID", "Customers"."Name", "Contacts"."Name", "Invoices"."InvoiceNo"
FROM
{oj (((((("GNManager"."dbo"."Invoices" "Invoices" LEFT OUTER JOIN "GNManager"."dbo"."DeliveryToInvoiceLink" "DeliveryToInvoiceLink" ON "Invoices"."ID"="DeliveryToInvoiceLink"."InvoiceID") LEFT OUTER JOIN "GNManager"."dbo"."Deliveries" "Deliveries" ON "DeliveryToInvoiceLink"."DeliveryID"="Deliveries"."ID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffToDeliveryLink" "CallOffToDeliveryLink" ON "Deliveries"."ID"="CallOffToDeliveryLink"."DeliveryID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffs" "CallOffs" ON "CallOffToDeliveryLink"."CallOffID"="CallOffs"."ID") LEFT OUTER JOIN ("GNManager"."dbo"."Projects" "Projects" LEFT OUTER JOIN "GNManager"."dbo"."Orders" "Orders" ON "Projects"."ID"="Orders"."ProjectID") ON "CallOffs"."OrderID"="Orders"."ID") INNER JOIN "GNManager"."dbo"."Customers" "Customers" ON "Orders"."CustomerID"="Customers"."ID") INNER JOIN "GNManager"."dbo"."Contacts" "Contacts" ON "Orders"."ContactID"="Contacts"."ID"}
WHERE
"Projects"."InternalRef"='12/4169'
ORDER BY
"Projects"."InternalRef" DESC, "Orders"."IntOrderNo" DESC
The above statement does work and produces everything that I need, but only if Invoices has an entry. If invoices is blank, nothing gets displayed.
The order of the tables in your join statement is the issue. Invoices being the first table is the one that will drive the rest of the results.
If you need all orders associated with your projects, no matter if there are any invoices, here's what I would do. Please note that you need valid values in Projects, Orders, Customers and Contacts, but everything else could be null.
select
Projects.ID
,Orders.IntOrderNo
,Deliveries.DeliveryNo
,Projects.InternalRef
,CallOffs.ID
,Customers.Name
,Contacts.Name
,Invoices.InvoiceNo
from
Projects
join Orders on Orders.ProjectID = Projects.ID
join Customers on Orders.CustomerID = Customers.ID
join Contacts on Orders.ContactID = Contacts.ID
left join Callofs on Callofs.OrderID = Orders.ID
left join CallOffToDeliveryLink on CallOffToDeliveryLink.CallOffID = Callofs.ID
left join Deliveries on CallOffToDeliveryLink.DeliveryID = Deliveries.ID
left join DeliveryToInvoiceLink on DeliveryToInvoiceLink.DeliveryID = Deliveries.ID
left join Invoices on DeliveryToInvoiceLink.InvoiceID = Invoices.ID
where
Projects.InternalRef = '12/4169'
order by
Projects.InternalRef desc
,Orders.IntOrderNo desc