I have three tables:
SN | Table Name | Primary Key | Foreign Key | Attribute
-----------------------------------------------------------------
1 | salesArea | salesAreaID | | areaDescription
2 | store | storeID | salesAreaID |
3 | salesPerson | salesPersonID | storeID | salesPersonName
I am trying to get the salesPersonName(s) of anyone that is in the same salesArea as a certain salesPerson.
For instance, a salesPerson named David works in storeID 23, which is in the NE salesArea.
There is another salesPerson named Bob working in storeID 34, which is also in the NE salesArea.
My query so far is...
SELECT salesPersonName,
salesPersonID,
st.salesAreaID,
areaDescription,
sp.storeId
FROM salesperson as sp, salesArea as sa, store as st
I am confused on how to get it get the storeID of 'David' and then retrieve what the salesArea is. Then with that salesArea, retrieve all salesPersons with that salesArea.
Salesperson table only gives the storeID, but then store gives the salesArea for the storeIDs.
Point in the right direction would be nice, join clause? some fancy where with a group by?
I am assuming:
Areas have stores
stores have salespersons
salespersons have names
So, we first want to find the area ID of the salesperson passed:
SELECT sp.SalesPersonID, st.SalesAreaID
FROM salesperson as sp
INNER JOIN store as st on sp.StoreID = st.StoreID
WHERE sp.SalesPersonName = 'David'
Now, we could use the results of this query to then execute the second part of the question, which is "get the other people in a given salesarea". If, for example, the above query returned SalesAreaID = 23 and SalesPersonID = 10, our second query would look like the following:
SELECT sp.SalesPersonID, sp.SalesPersonName, st.StoreID
FROM stores st
INNER JOIN salespersons sp on st.StoreID = sp.StoreID
WHERE st.SalesAreaID = 23 and sp.SalesPersonID <> 10
But, we can combine the two queries to form a single one that does the same thing:
SELECT sp2.SalesPersonID, sp2.SalesPersonName, st2.StoreID
FROM salesperson as sp
-- Join to stores to get the areaID of the salesperson passed (multiplicity 1)
INNER JOIN store as st on sp.StoreID = st.StoreID
-- self join to store to get all stores in that area (multiplicity 1 x Stores[area])
INNER JOIN store as st2 on st.SalesAreaID = st2.SalesAreaID
-- get all salespersons assigned to all stores in the area (multiplicity 1 x salespersons[area])
INNER JOIN salesperson as sp2
on st2.StoreID = sp2.StoreID
-- only return "other" salespersons
and sp2.SalesPersonID <> sp.SalesPersonID
WHERE sp.SalesPersonName = 'David'
Et voilĂ , we have a query giving all other salespersons in a the same area as a passed salesperson.
Related
I am trying to use MS-Access to create a database of files. These files can be charged out to employees for review.
I have a table for the inventory, a table for employees, and a "charge out" table that includes a file, what employee it is being charged out to, and the date this happened.
My goal is to create a query that shows the file inventory and its details, and the location as to where it is currently located (e.g. with an employee, or in storage).
I have the following query called Most_Recent_Change:
SELECT Inventory.File_Number, Inventory.Last_Name, Inventory.First_Name,
Max([Charge_In/Out].Date_Changed) AS Current_Location_Date
FROM Inventory INNER JOIN [Charge_In/Out] ON Inventory.HRMIS = [Charge_In/Out].File_HRMIS
GROUP BY Inventory.File_Number, Inventory.Last_Name, Inventory.First_Name;
This returns the information from the file, and the most recent date from the charge out table.
What I need is this table, with each file from the inventory showing up exactly once, with the most recent date, but I also need the location that is associated with the most current date. Adding the location to this query creates duplicates from the inventory which I cannot have.
I created another query which I believe is more complete:
SELECT Inventory.File_Number, Inventory.Last_Name, Inventory.First_Name, [Charge_In/Out].Date_Changed AS
Current_Location_Date, Location.Location_Name
FROM Location INNER JOIN (Inventory INNER JOIN [Charge_In/Out] ON Inventory.File_Number =
[Charge_In/Out].File_Number) ON Location.Location_Name = [Charge_In/Out].Charge_Out_Location
WHERE Current_Location_Date =
(SELECT MAX(Date_Changed)
FROM [Charge_In/Out]);
This prompts access to ask for the parameter value for Current_Location_Date, which it should not be, it should be taking the max date for each entry in the inventory.
For reference, this is what the Charge out table looks like:
LogNumber | File_Number | Charge_Out_Location | Date_Changed
1 xxx1 Storage 2019-01-01
2 xxx1 Analyst 2020-05-01
3 xxx1 Storage 2020-10-02
4 xxx2 Storage 2019-01-01
And the resulting table that I need would look like:
File_Number | Last_Name | First_Name | Current_Location | Current_Location_Date
xxx1 SMITH John Storage 2020-10-02
xxx2 SMITH Jane Storage 2019-01-01
Try using your first result-set like a virtual table.
SELECT Inventory.File_Number, Inventory.Last_Name, Inventory.First_Name,
MaxInventory.Current_Location_Date, Charge.Charge_Out_Location
FROM Inventory
INNER JOIN (
SELECT Inventory.File_Number, Max([Charge_In/Out].Date_Changed) AS Current_Location_Date
FROM Inventory INNER JOIN [Charge_In/Out] ON Inventory.HRMIS = [Charge_In/Out].File_HRMIS
GROUP BY Inventory.File_Number
) AS MaxInventory ON Inventory.File_Number = MaxInventory.File_Number
INNER JOIN [Charge_In/Out] AS Charge ON Inventory.HRMIS = Charge.File_HRMIS
AND Charge.Date_Changed = MaxInventory.Current_Location_Date
The concept is to get the summary as a virtual table (ie "query"). It has minimum info, so it is easy to join-to, and without duplicate lines. Give it an alias MaxInventory. Then join the rest of your info to MaxInventory, which is already minimized/summarized.
You can also just create a new "query" in MS Access to do the same thing, and it is more-permanent, instead of creating it inline, like I did.
The query changes when you have multiple check-ins for the same date and you only want the newest, per-file:
SELECT Inventory.File_Number, Inventory.Last_Name, Inventory.First_Name,
Charge.Date_Changed AS Current_Location_Date, Charge.Charge_Out_Location
FROM (
SELECT Inventory.File_Number, Max([Charge_In/Out].LogNumber) AS MaxLogNumber
FROM Inventory INNER JOIN [Charge_In/Out] ON Inventory.HRMIS = [Charge_In/Out].File_HRMIS
GROUP BY Inventory.File_Number
) AS MaxCharge
INNER JOIN [Charge_In/Out] AS Charge ON MaxCharge.MaxLogNumber = Charge.LogNumber
INNER JOIN Inventory ON Inventory.File_Number = MaxCharge.File_Number
AND Inventory.HRMIS = Charge.File_HRMIS
I have two tables Price(Type, Values) and Product(Seat) and some values.
Price | Product
-------------+---------
Type Values | Seat
S 4 | FO
P 6 | CA
| FA
I know that [FO] and [CA] belong to type [P], and [FA] belongs to type [S]. How can I join these tables and shows associated type and values:
Results
Seat Type Values
----- ----- -----------
FO P 6
CA P 6
FA S 4
You can join the tables like this:
select pr.seat, sum(p.value)
from price p join
product pr
on pr.seat in ('FO', 'CA') and p.type = 'P' or
pr.seat in ('FA') and p.type = 'S'
group by pr.seat;
That said, you should have a proper table that connects the seats to the products, probably called ProductSeats with one row per product and matching seat.
I would use a derived table to store the mapping between price and seat. This is easily extensible when new requirements come up.
SELECT pri.*, pro.*
FROM price pri
INNER JOIN (
SELECT 'FO' seat, 'P' price
UNION ALL SELECT 'CA' seat, 'P' price
UNION ALL SELECT 'FA' seat, 'S' price
) map ON map.pri = pri.price
INNER JOIN product pro ON pro.seat = map.pro
This can be simplified by using the VALUES() syntax:
SELECT pri.*, pro.*
FROM price pri
INNER JOIN (
VALUES('FO', 'P'), ('CA', 'P'), ('FA', 'S')
) AS map(seat, price) ON map.pri = pri.price
INNER JOIN product pro ON pro.seat = map.pro
i haven't really touched much of PL/SQL before this project and my current knowledge of DBs is limited to SQLite, MySQL, PostgreSQL and other non sql DB technologies so bear with me on this.
First i started with a query that would get me the max difference in hours between two dates for each ID i had on that table. It goes something like this:
SELECT
id_trip as ID,
MAX(24 * (Trip.actual_arrival_date- (Trip.programmed_arrival_date))) as MAX_DELAY_HOURS
FROM Trip
GROUP BY ID
And that returns me something like this:
Results of first query
So i can say that i successfully went into the all the trips that exist for each ID and got the ones that have the maximum delay.
Now what i want to do after that is to join other types of information to that table, namely the actual date of the trip, the name of the departure spot and the name of the arrival spot. So i did something like this:
SELECT
internal_ID as external_ID,
programmed_date,
starting_airport.name as starting_airport,
destination_airport.name as destination_airport,
24 * (Trip.actual_arrival_date- (Trip.programmed_arrival_date)) AS external_delay
FROM Regular_flight
INNER JOIN Trip ON Regular_flight.ID = Trip.ID_Regular_flight
INNER JOIN Flight ON Regular_flight.ID_Flight = Flight.ID
INNER JOIN Airport starting_airport ON starting_airport.ID_IATA = Flight.ID_STARTING_AIRPORT
INNER JOIN Airport destination_airport ON destination_airport.ID_IATA = Voo.ID_DESTINATION_AIRPORT
INNER JOIN (
--this is the query that i built before--
SELECT
id_trip as internal_ID,
MAX(24 * (Trip.actual_arrival_date- (Trip.programmed_arrival_date))) as MAX_DELAY_HOURS
FROM Trip
GROUP BY ID
) ON internal_ID = external_ID
Order by external_ID;
And this actually returns something like this:
Results of second query
Now my problem is that while i have all the info i need there... i wanted to filter it out so that it only shows me the highest EXTERNAL_DELAY for each EXTERNAL_ID.
Usually i'd do a GROUP BY EXTERNAL_ID but since i'm selecting many things not just EXTERNAL_ID it won't actually execute the code. I've tried to do a GROUP BY with all the columns i'm selecting in the external query but then i have all the "combinations" between the external_ID and Programmed_date which is not what i'm looking for.
Basically from the 2nd query i want to reach something like this:
| EXTERNAL_ID | PROGRAMMED_DATE | STARTING_AIRPORT | DESTINATION_AIRPORT | EXTERNAL_DELAY |
| 1 | 16.07.08 | Aeroporto de Gatwick | Aeroporto Francisco Sa Carneiro | 744 |
| 2 | 16.08.08 | Aeroporto de Gatwick | Aeroporto Francisco Sa Carneiro | 0 |
| 3 | 16.08.09 | Aeroporto Francisco Sa Carneiro | Aeroporto Francisco Sa Carneiro | 744 |
And so on for each ID, so basically for each ID the the MAXIMUM delay found no matter what the date is.
I've been scratching my head for a few hours now and i'd like to have someone point me out in the right direction.
Appreciate any help i can get.
SELECT *
FROM
(SELECT x.*,
ROW_NUMBER() OVER (PARTITION BY external_ID ORDER BY external_delay DESC NULLS LAST) r
FROM (
SELECT internal_ID AS external_ID,
programmed_date,
starting_airport.name AS starting_airport,
destination_airport.name AS destination_airport,
24 * (Trip.actual_arrival_date- (Trip.programmed_arrival_date)) AS external_delay
FROM Regular_flight
INNER JOIN Trip
ON Regular_flight.ID = Trip.ID_Regular_flight
INNER JOIN Flight
ON Regular_flight.ID_Flight = Flight.ID
INNER JOIN Airport starting_airport
ON starting_airport.ID_IATA = Flight.ID_STARTING_AIRPORT
INNER JOIN Airport destination_airport
ON destination_airport.ID_IATA = Voo.ID_DESTINATION_AIRPORT
INNER JOIN
(
--this is the query that i built before--
SELECT id_trip AS internal_ID,
MAX(24 * (Trip.actual_arrival_date- (Trip.programmed_arrival_date))) AS MAX_DELAY_HOURS
FROM Trip
GROUP BY ID
)
ON internal_ID = external_ID
) x) WHERE r =1
Order by external_ID;
I have 3 tables I need to put together.
The first table is my main transaction table where I need to get distinct transaction id numbers and company id. It has all the important keys. The transaction ids are not unique.
The second table has item info which is linked to transaction id numbers which are not unique and I need to pull items.
The third table has company info which has company id.
Now I've sold some of these with the first one through a group by id. The second through a subquery which creates unique ids and joins onto the first one.
The issue I'm having is the third one by company. I cannot seem to create a query that works in the above combinations. Any ideas?
As suggested here is my code. It works but that's because for the company I used count which doesn't give the correct number. How else can I get the company number to come out correct?
SELECT
dep.ItemIDAPK,
dep.TotalOne,
dep.company,
company.vendname,
appd.ItemIDAPK,
appd.ItemName
FROM (
SELECT
csi.ItemIDAPK,
sum(f.TotalOne) as TotalOne,
count(f.DimCurrentcompanyID) company
FROM dbo.ReportOne F with (nolock)
INNER JOIN dbo.DSaleItem csi with (nolock)
on f.DSaleItemID = csi.DSaleItemID
INNER JOIN dbo.DimCurrentcompany cv
ON f.DimCurrentcompanyID = cv.DimCurrentcompanyID
INNER JOIN dbo.DimDate dat
on f.DimDateID = dat.DimDateID
where (
dat.date >='2013-01-29 00:00:00.000'
and dat.date <= '2013-01-30 00:00:00.000'
)
GROUP BY csi.ItemIDAPK
) as dep
INNER JOIN (
SELECT
vend.DimCurrentcompanyID,
vend.Name vendname
FROM dbo.DimCurrentcompany vend
) As company
on dep.company = company.DimCurrentcompanyID
INNER JOIN (
SELECT
c2.ItemIDAPK,
ItemName
FROM (
SELECT DISTINCT ItemIDAPK
FROM dbo.dimitem AS C
) AS c1
JOIN dbo.dimitem AS c2 ON c1.ItemIDAPK = c2.ItemIDAPK
) as appd
ON dep.ItemIDAPK = appd.ItemIDAPK
For further information my output is the following example, I know the code executes and the companyid is incorrect as I just put it with a (count) in their to make the above code execute:
Current Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 303 Johnson Corp 29323 Soap
Proposed Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 29 Johnson Corp 29323 Soap
I've 3 Tables
Personel : id, name
Department : id, name
Match_Dept_Per : dept_id, pers_id, workInfo
Foreign Keys :
dept_id --> Department.id
pers_id --> Personel.id
Example Data :
Personel :
1, Emir Civas
2, Sercan Tuncay
Department :
1, Sales
2, Planning
Match_Dept_Per :
1,1,Manager
What I'm trying to do is, listing peoples names, their department names and workInfos like:
ID | Pers. Name | Dept Name | Work Info
---------------------------------------
1 | Emir Civas | Sales | Manager
I can do this with a simple select query:
select p.id, p.name, d.name, m.workInfo
from personel p, department d, match_dept_per m
where p.id = m.pers_id and d.id = m.dept_id;
Here is sample fiddle of my schema and this query.
However what I need is to display other persons that their id's are not inserted to match_dept_per table. And Set "Unknown" As the Null Values. Like:
ID | Pers. Name | Dept Name | Work Info
------------------------------------------
1 | Emir Civas | Sales | Manager
2 | Sercan Tuncay | Unknown | Unknown
Since I'm Using Match_Dept_Per Table, If Personel ID isn't Added, I can't do anything.
Any suggestions ?
Use left outer join to include all persons even if they are not associated with the other tables:
select p.id,
p.name,
ifnull(d.name, 'Unknown') DepName,
ifnull(m.workInfo, 'Unknown') workInfo
from personel p
left outer join match_dept_per m
on p.id = m.pers_id
left outer join department d
on d.id = m.dept_id
Here is a demo fiddle.
As you seem to use MS SQL, you might need to use isnull() instead of ifnull(). But I would ommit that anyway because I think it's better to have a NULL in the code where you use the data (Java, C#, whatever). You can control the output there.