I have a database with 3 tables; tblCustomers, tblBookings, tblFlights.
In the Bookings table I have the number of tickets sold for each flight, and in the Flight table the Capacity of each flight. I want to return the remaining number of tickets left for each flight.
I have tried subtracting the capacity from the tickets, but can't get the syntax right, I know I have created a JOIN and it does not return the correct information.
I have tried:
SELECT *, (Capacity - Tickets)
from tblFlights, tblBookings
where (Capacity - Tickets)
You are actually cross joining the tables, but you should do an INNER or LEFT join based on the related columns of the tables, which I believe must have names like flight_id:
select *, (f.Capacity - b.Tickets) tickets_left
from tblFlights f inner join tblBookings b
on b.flight_id = f.flight_id
where (f.Capacity - b.Tickets) > 0
I kept the where clause because you use it in your code.
If the relation of tblFlights and tblBookings is not 1:1 then you also need aggregation:
select f.*, (f.Capacity - coalesce(b.Tickets, 0)) tickets_left
from tblFlights f left join (
select flight_id, sum(Tickets) Tickets
from tblBookings
group by flight_id
) b on b.flight_id = f.flight_id
Your syntax should be something like this:
SELECT *, (Capacity - Tickets) as Remaining
from tblFlights Tf, tblBookings Tb
where Tb.id = Tf.id and (Capacity - Tickets) > 0
You can also use a join statement:
SELECT *, (Capacity - Tickets) as Remaining
from tblFlights Tf
join tblBookings Tb on (Tf.id = Tb.id)
where (Capacity - Tickets) > 0
What you had initially creates permutations between the two tables.
Related
enter image description hereI have three tables that want to make some calculation based on. However, what I stated in the below did not work.
Could someone give me Any feedback?
Thank you,
formula:
(runnincost/total(gas_production of eacy year))*gas_production of each year)
as:
CTE c (id,filed,year_1,year_2,year_3)
as( select g.id, g.field,
(r.year_1/sum(g.year_1))*g.year_1 ,
(r.year_2/sum(g.year_2))*g.year_2 ,
(r.year_3/sum(g.year_3))*g.year_3 ,
from group_1 as g
inner join ref_fee as r
on r.id=g.id
group by g.field )
select c.id, c.filed,
c.year_1*b.year_1 as year_1,
c.year_2*b.year_2 as year_2,
c.year_3*b.year_3 as year_3
from c
inner join back b
on b.id=c.id
group by c.field;
"Did not work" is difficult to debug.
What is evident is that tables' aliases - in Oracle - can't have the AS keyword (columns can). When fixed, query looks like this:
WITH
c (id,
filed,
year_1,
year_2,
year_3)
AS
( SELECT g.id,
g.field,
(r.year_1 / SUM (g.year_1)) * g.year_1,
(r.year_2 / SUM (g.year_2)) * g.year_2,
(r.year_3 / SUM (g.year_3)) * g.year_3
FROM group_1 g INNER JOIN ref_fee r ON r.id = g.id
GROUP BY g.field)
SELECT c.id,
c.filed,
c.year_1 * b.year_1 AS year_1,
c.year_2 * b.year_2 AS year_2,
c.year_3 * b.year_3 AS year_3
FROM c INNER JOIN back b ON b.id = c.id
GROUP BY c.field;
I have no idea whether it'll work or not as I don't have your tables, nor I know what "calculations" you're about to perform.
Could you explain how I get this particular table result?
My 4 queries to individually get each column separately are also below.
I am not sure on method here do I nest the last 3 queries into the first or do I use a union between the queries.
Bearing in mind that the information in each one doesn't really match I assume Union or Union All isn't going to be useful.
Would a derived table be a better method. Sorry my SQL skills are fairly basic.
I need to also retain the ability to 'tweak' the where clauses as my admin decides to exclude certain records later (you IT folks will be used to that!)
Some the ability to alter the where clauses would be good in a solution.
Just to make it more annoying for ya ;-)
Query table would need to look a little like this
Company Department Total_B Total_R Total_Ret RushJobs
ACME LSD 2 100 24 3
The four queries (that work separately to get each column above are here ( I have left in the respective Group By and where clauses incidentally I_Department does map to just Department in the case of 2nd query.
-- Total B count query from B
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company;
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment
-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department
-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department
So final table
<table><TBODY>
<TR>
<TH>Company</TH>
<TH>Department</TH>
<TH>Total_B</TH>
<TH>Total_R </TH>
<TH>Total_Ret</TH>
<TH>RushJobs</TH></TR>
<TR>
<TD>ACME</TD>
<TD>LSD</TD>
<TD>100</TD>
<TD>2</TD>
<TD>4</TD>
<TD>1</TD></TR></TBODY></table>
One approach would be to use a Common table expression (CTE) aka with statement..
This allows each query to continue to be independent allowing you to easily twerk (I was going to correct that typo but it was just too funny) the where clauses for each and combines the results in the end returning 1 record with 4 columns.
-- Total B count query from B
With B as (
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company),
H as (
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment),
R as (-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department),
RushJobs as (-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department)
SELECT coalesce(B.Company, R.Company, RJ.Company)
, coalesce(B.Department,R.Department, Rj.Department)
, B.Total_B, H.Total_R, R.Total_Ret, RJ.RushJobs
FROM
FULL OUTER JOIN H
on B.Company = H.Company
FULL OUTER JOIN R
on B.company = R.Company
and B.Department = R.Department
FULL OUTER JOIN RushJobs RJ
on H.company = RJ.Company
and H.Department = RJ.Department
I have a data table with destinations and LAT/LON data (~100K records)
DESTINATIONS {
id,
lat,
lon,
...
}
Now I need to insert distances into a new table...
DISTANCES {
id_a,
id_b,
distance
}
What's the best way to do that?
I don't need all data (cartesian product), only the 100 closest.
No duplicates (a_id+b_id == b_id+a_id), e.g. [NYC:Chicago] == [Chicago:NYC] (same distance)
Not by itself (a_id != b_id), because it 0 miles from [NYC:NYC] ;)
This is the calculation (in kilometers/meters):
ROUND(111045
* DEGREES(ACOS(COS(RADIANS(A.lat))
* COS(RADIANS(B.lat))
* COS(RADIANS(A.lon) - RADIANS(B.lon))
+ SIN(RADIANS(A.lat))
* SIN(RADIANS(B.lat)))),0)
AS 'distance'
Okay, the JOIN is no problem, but how can I implement the three "filters"?
Maybe with a WHILE loop and SUBSELECT LIMIT/TOP 100 ORDER BY distance ASC?
Or is it also possible to INSERT by JOIN?
Does somebody have a idea?
Psuedocode:
INSERT INTO [newTable] (ColumnList...)
SELECT TOP 100 a.id, b.id, DistanceFormula(a.id, b.id)
FROM Destination a
CROSS JOIN Destination b
WHERE a.id<b.id
ORDER BY DistanceFormula(a.id, b.id) ASC
EDIT to get 100 b for every a:
INSERT INTO [newTable] (ColumnList...)
SELECT a.id, b.id, DistanceFormula(a.id, b.id)
FROM Destination a
INNER JOIN Destination b
ON b.id=(
SELECT TOP 100 c.id
FROM Destination c
WHERE a.id<c.id
ORDER BY DistanceFormula(a.id, c.id) ASC
)
I've simplified it (distcalc)...
INSERT INTO [DISTANCES] (id_a, id_b, distance)
SELECT
A.id,
B.id,
25 /*ROUND(111045 * DEGREES(ACOS(COS(RADIANS(A.geo_lat)) * COS(RADIANS(B.geo_lat)) * COS(RADIANS(A.geo_lon) - RADIANS(B.geo_lon)) + SIN(RADIANS(A.geo_lat)) * SIN(RADIANS(B.geo_lat)))),0)*/
FROM [DESTINATIONS] AS A
INNER JOIN [DESTINATIONS] AS B
ON b.id IN(
SELECT TOP 100
C.id
FROM [DESTINATIONS] AS C
WHERE
A.id < C.id
ORDER BY A.id /*ROUND(111045 * DEGREES(ACOS(COS(RADIANS(A.geo_lat)) * COS(RADIANS(C.geo_lat)) * COS(RADIANS(A.geo_lon) - RADIANS(C.geo_lon)) + SIN(RADIANS(A.geo_lat)) * SIN(RADIANS(C.geo_lat)))),0)*/ ASC
)
You mean like this?
Okay. That works. :)
But it is definitely too slow!
I'll program a routine that returns only the 100 nearest results on request.
And another (sub) routine will insert/update these (program-sided) results with timestamp into the distances table, so that it's possible to accessed to any existing results by the next call.
But thank you very very much! :)
I am trying to find the most efficient way to build a counter warehouse.
shortened the tables just to needed info for question
Match Table
MatchId, version, type
MatchParticipants
matchId, playerid, characterid, teamid (only team1 or team2), winner (1 or 0)
10 of these rows per match
Characters
characterid, name
So i have thought of doing a cross join of characters on characters and that gives me all the possibilities of opponents for said character then i would have do a massive subquery to look into the matches table where the id's were on opposite teams.
Any ideas essentially what i see the warehouse table looking like.
character1.characterid, character1.name,
character2.characterid, character2.name,
winrate of character1 over character2
I think that this query should meet your expectations:
SELECT x.[first] AS CharacterId,
c.name,
x.[second] AS CharacterId,
c1.name,
wins/loses AS ratio
FROM
(
SELECT m.CharacterId [first],
m1.CharacterId [second],
SUM(m.winner) AS wins,
SUM(m1.winner) AS loses
FROM MatchParticipants m
INNER JOIN MatchParticipants m1 ON m.MatchId = m1.MatchId AND m.TeamId <> m1.TeamId
GROUP BY
m.CharacterId,
m1.CharacterId
) x
LEFT JOIN Characters c ON x.[first] = c.characterid
LEFT JOIN Characters c1 ON x.[second] = c1.characterid
is this what you're looking for?
SELECT
*,
100.0 * matches/wins AS winRate
FROM
(SELECT
teamid,
playerid,
characterid AS opponentID,
COUNT(matchId) AS matches,
SUM(winner) AS wins
FROM
MatchParticipants
GROUP BY
teamid,
playerid,
characterid) w
I have 2 tables Tblinkreceiving and Tblinkdelivery. I want to display the Stock balance for each inkcode.I tried the below sql join query but the calculation is wrong for many inkcodes when i cross check in manual calculation.Where it went wrong ?
select r.inkcode, SUM(r.quantity) Stock-In, SUM(d.quantity) Stock-out, (SUM(r.quantity) - SUM(d.quantity)) Stock-Balance from Tblinkreceiving r,Tblinkdelivery d where r.inkcode=d.inkcode
group by r.inkcode;
WITH i AS
(
SELECT inkcode, SUM(quantity) AS qin
FROM tblInkReceiving
GROUP BY
inkcode
),
o AS
(
SELECT inkcode, SUM(quantity) AS qout
FROM tblInkDelivery
GROUP BY
inkcode
)
SELECT COALESCE(i.inkcode, o.inkcode) AS inkcode,
COALESCE(qin, 0) AS stock_in,
COALESCE(qout, 0) AS stock_out,
COALESCE(qin, 0) - COALESCE(qout, 0) AS stock_balance
FROM i
FULL JOIN
o
ON o.inkcode = i.inkcode
You have used an inner join (implicit) to combine receiving and delivery. This means that any ink code that has been received but not delivered will be excluded from your results.
If you can make the assumption that for any ink delivery there must be an ink receipt (based on the premise that you cannot deliver something that you haven't received), then you can use an inner join on tblInkReceiving, as follows:
SELECT r.inkcode,
SUM(r.quantity) AS Stock-In,
ISNULL(SUM(d.quantity), 0) AS Stock-out,
SUM(r.quantity) - ISNULL(SUM(d.quantity), 0) AS Stock-Balance
FROM Tblinkreceiving r LEFT JOIN Tblinkdelivery d ON r.inkcode = d.inkcode
GROUP BY r.inkcode
The left join will return all records on the left (r), including matching records on the right (d). If d has not matching records (i.e. there have been no ink deliveries for that ink code), then the values for those rows will be null.
If you cannot make the assumption that ink can only be delivered once it has been received, then you need to either link to the ink table as well (i.e. the table for which inkcode is the primary key), or union all of the ink codes in the receiving and delivery tables, and link to that:
;WITH cte AS (SELECT inkcode FROM Tblinkreceiving
UNION
SELECT inkcode FROM Tblinkdelivery)
SELECT cte.inkcode,
SUM(r.quantity) AS Stock-In,
ISNULL(SUM(d.quantity), 0) AS Stock-out,
SUM(r.quantity) - ISNULL(SUM(d.quantity), 0) AS Stock-Balance
FROM cte LEFT JOIN Tblinkreceiving r ON cte.ink_code = r.ink_code
LEFT JOIN Tblinkdelivery d ON cte.inkcode = d.inkcode
GROUP BY cte.inkcode