SQL how to count free reservations - sql

I have 2 tables
Reservations
reservation no | trip ID |person ID| Status
1 | 2 | 1 | C '
2 | 3 | 2 | P '
3 | 4 | 3 | P '
4 | 1 | 4 | C '
5 | 1 | 6 | P '
6 | 1 | 7 | P '
7 | 2 | 5 | P '
Where P stands for payed and C for Cancelled
And trips
trip ID |trip Name|Date | Free Places
1 | Paris |2016-12-18| 5 '
2 | New York|2016-12-17| 6 '
3 | Warsaw |2016-12-15| 5 '
4 | London |2016-12-20| 10 '
I want to select number of left free places for each trip
trip ID |trip Name|Date | Free Places | Left free Spaces
1 | Paris |2016-12-18 | 5 | 3
2 | New York| 2016-12-17 | 6 | 5
3 | Warsaw |2016-12-15 | 5 | 4
4 | London |2016-12-20 | 10 | 9

One approach would be to use a subquery of the reservation table which computes the number of spaces already taken for each trip. Then join this back to the trips table to compute the number of spaces remaining.
SELECT t1.tripID,
t1.tripName,
t1.Date,
t1.FreePlaces,
t1.FreePlaces - COALESCE(t2.numBooked, 0) AS left_free_spaces
FROM trips t1
LEFT JOIN
(
SELECT tripID, SUM(CASE WHEN Status = 'P' THEN 1 ELSE 0 END) AS numBooked
FROM Reservations
GROUP BY tripID
) t2
ON t1.tripID = t2.tripID

Try this code.it may help you
create table #RESERVATION (revservation_no bigint,trip_ID bigint,person_id bigint,status char(5))
insert into #RESERVATION values(1,2,1,'C'),(2,3,2,'P'),(3,4,3,'P'),(4,1,4,'C'),(5,1,6,'P'),(6,1,7,'P'),(7,2,5,'P')
CREATE TABLE #TRIP (TRIP_ID BIGINT,TRIP_NAME VARCHAR(50),DATE_ DATE ,FREE_PLACES BIGINT)
INSERT INTO #TRIP VALUES (1,'PARIS','2016-12-18',5),(2,'NEW YORK','2016-12-17',6),(3,'WARSAW','2016-12-15',5),(4,'LONDON','2016-12-20',10)
;WITH CTE AS(
SELECT DISTINCT T.TRIP_ID,T.TRIP_NAME,T.DATE_,T.FREE_PLACES,COUNT(revservation_no)AS LEFT_SPACES FROM #TRIP T
INNER JOIN #RESERVATION R ON R.trip_ID=T.TRIP_ID
WHERE status='P'
GROUP BY T.TRIP_ID,T.TRIP_NAME,T.DATE_,T.FREE_PLACES
)
SELECT TRIP_ID,TRIP_NAME,DATE_,FREE_PLACES,FREE_PLACES-LEFT_SPACES AS LEFT_FREE_PLACES FROM CTE

Select D1.trip_ID ,trip_Name, [Date] , D1.Free_Places,
D1.Free_Places - Sum(Case
When D2.Status = 'P' then 1
Else 0
End) as Left_free_Spaces
From Trips D1
Inner Join Reservations D2
On D1.trip_ID = D2.trip_ID
Group by D1.trip_ID ,trip_Name, [Date] , Free_Places

Related

How to get count from one table which is mutually dependent to another table

I have two table
Let's name as first table: QC_Meeting_Master
Second table: QC_Project_Master I want to calculate count of problems_ID Which is mutually depend on second table
ID | QC_ID | Problems_ID |
___|_______|_____________|
1 | 1 | 2 |
2 | 1 | 7 |
ID | QC_ID | Problem_ID |
___|_______|_____________|
1 | 1 | 7 |
2 | 1 | 7 |
3 | 1 | 7 |
4 | 1 | 7 |
5 | 1 | 2 |
6 | 1 | 2 |
7 | 1 | 2 |
select COUNT(Problem_ID) from [QC_Project_Master] where Problem_ID in
(select Problems_ID from QC_Meeting_Master QMM join QC_Project_Master QPM on QMM.Problems_ID = QPM.Problem_ID)
I have to calculate Count of QC_Project_Master (problem_ID) on basis of QC_Meeting_Master (Problems_ID)
it means for first table: QC_Meeting_Master(Problems_ID) = 2,
then count should be 3
And for Second table: QC_Project_Master (Problems_ID) = 7,
then count should be 4
use conditional aggregation
select sum(case when t2.Problem_ID=2 then 1 else 0 end),
sum(case when t2.Problem_ID=7 then 1 else 0 end) from
table1 t1 join table2 t2 on t1.QC_ID=t2.QC_ID and t1.Problems_ID=t2.Problems_ID
if you need all the group count then use below
select t2.QC_ID,t2.Problems_ID, count(*) from
table1 t1 join table2 t2
on t1.QC_ID=t2.QC_ID and t1.Problems_ID=t2.Problems_ID
group by t2.QC_ID,t2.Problems_ID
As far as I understood your problem this is simple aggregation and JOIN as below:
SELECT mm.QC_ID, mm.Problem_ID, pm.cnt
FROM QC_Meeting_Master mm
INNER JOIN
(
SELECT QC_ID, Problem_ID, COUNT(*) cnt
FROM QC_Project_Master
GROUP BY QC_ID, Problem_ID
) pm
ON pm.QC_ID = mm.QC_ID AND pm.Problem_ID = mm.Problem_ID;

Get right table data on LEFT JOIN

I have a problem with my sql join request.
I need to get lines of left table who are not referenced in right table for ME (User 1) or referenced in right table with status equal to 0 and user equal to 1.
I also need the field status of right table.
Here is my two tables :
Table left
ID | title
1 | Title 1
2 | Title 2
3 | Title 3
4 | Title 4
5 | Title 5
6 | Title 6
Table right
ID | status | user | left_id
1 | 0 | 1 | 1
2 | 0 | 50 | 1
3 | 1 | 1 | 2
4 | 0 | 50 | 2
5 | 0 | 1 | 3
6 | 1 | 50 | 3
7 | 0 | 50 | 4
8 | 1 | 50 | 5
My goal is to get this result :
left.ID | left.title | right.status | right.user
1 | Title 1 | 0 | 1
3 | Title 3 | 0 | 1
4 | Title 4 | NULL | NULL
5 | Title 5 | NULL | NULL
6 | Title 6 | NULL | NULL
Here is my request for the moment :
SELECT l.id, l.title, r.user, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id
WHERE r.left_id IS NULL or (r.user = 1 AND r.status = 0)
With this request I get lines ID (left table) 1 / 3 / 6. But I also need the ID 4 / 5.
Those lines isn't displayed because another user (50) as a reference, but it's not me (1).
If someone can help me to add line 4 / 5 to my result I would be happy.
Thanks
Small improvement of the query should be sufficient:
SELECT l.id, l.title, r.user, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id and r.user = 1
WHERE r.left_id IS NULL or r.status = 0
(Select t1.id, t1.title,t2.status,t2.user
from tableLeft t1
right outer join tableRight t2 on t2.left_id=t1.id
where t1.id not in
(select tt2.left_id from tableRight tt2)
)
union
(select t1.id,t1.title,t2.status,t2.user
from tableLeft t1
left join tableRight t2 on t1.id=t2.left_id
where t2.status=0 and t2.user=1
)

Expand header row into multiple child rows

Within my SQL database I have a table which represents books of tickets [Books] where the number of tickets within a book can vary.
This is represented by two columns [Books].[StartNo] and [Books].[BookSize]
What I need to achieve is a select statement that repeats each row in the table [Books] for each ticket in that book with an additional calculated column that displays the ticket number for that row.
So from
--------+---------+----------
Book | StartNo | BookSize
--------+---------+----------
Book 1 | 1 | 3
Book 2 | 4 | 4
Book 3 | 19 | 4
to something like this
--------+---------+----------+----------
Book | StartNo | BookSize | TicketNo
--------+---------+----------+----------
Book 1 | 1 | 3 | 1
Book 1 | 1 | 3 | 2
Book 1 | 1 | 3 | 3
Book 2 | 4 | 4 | 4
Book 2 | 4 | 4 | 5
Book 2 | 4 | 4 | 6
Book 2 | 4 | 4 | 7
Book 3 | 19 | 4 | 19
Book 3 | 19 | 4 | 20
Book 3 | 19 | 4 | 21
Book 3 | 19 | 4 | 22
I'm just not quite sure where to start.
Try this:
;WITH Counts AS (
SELECT Max(StartNo + BookSize) AS TotalBookSize
FROM t
), CTE(Tickets) AS (
SELECT 1
UNION ALL
SELECT Tickets + 1
FROM CTE
WHERE Tickets < (SELECT TotalBookSize FROM Counts)
)
SELECT *
FROM t JOIN CTE ON CTE.Tickets BETWEEN t.StartNo AND t.StartNo + t.BookSize - 1
Use tally table
WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0)
,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) --10 * 10 = 100
,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv0 b) --100 * 10 = 1000
,Tally (num) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv2)
SELECT (num+StartNo-1) as TicketNo, *
FROM Tally
CROSS JOIN Yourtable
WHERE num <= booksize
ORDER BY book
you need a list of numbers and join it with the books table
select b.*, number
from Books b
join master.dbo.spt_values v on v.number between b.StartNo AND b.StartNo+b.BookSize-1

Difficult query in either Linq To Sql or SQL

I've been working on this for 2 days and I can't figure it out. I'm hoping someone smarter than me will give this a go.
Let's say I have the following tables:
Rating:
Id | Name
1 | A
2 | B
3 | C
4 | D
5 | E
Inspection:
Id | Date (mm/dd/yyyy)
1 | 01/04/2012
2 | 04/04/2012
3 | 28/03/2012
4 | 04/04/2012
Observation:
Id | InspectionId | RatingId
1 | 2 | 3
2 | 1 | 2
3 | 4 | 3
4 | 2 | 1
5 | 3 | 3
6 | 1 | 2
I want the query to return:
RatingName | Date(mm/dd/yyyy) | ObservationCount
A | 01/04/2012 | 0
B | 01/04/2012 | 1
C | 01/04/2012 | 1
D | 01/04/2012 | 0
E | 01/04/2012 | 0
A | 04/04/2012 | 1
B | 04/04/2012 | 0
C | 04/04/2012 | 2
D | 04/04/2012 | 0
E | 04/04/2012 | 0
A | 28/03/2012 | 0
B | 28/03/2012 | 0
C | 28/03/2012 | 1
D | 28/03/2012 | 0
E | 28/03/2012 | 0
So I need the number of Observations for each rating for each date. And yes I need to have the records which return 0 Observations because I'm using this data in a stacked chart and without them it throws an error. I've managed to get the above table but without the records that return 0 Observations with the following Linq To Sql query, but from this point I get stuck.
MyDataContext DB = new MyDataContext();
var data =
(from r in DB.Ratings
join o in DB.Observations on r.Id equals o.RatingId into ro
from observation in ro.DefaultIfEmpty()
join i in DB.Inspections on observation.InspectionId equals i.Id into roi
from q in roi.DefaultIfEmpty()
group q by new { Name = r.Name, Date = q.Date } into grouped
select
new
{
RatingName = grouped.Key.Name,
Date = grouped.Key.Date,
ObservationCount = grouped.Count(x => x != null)
}).OrderBy(x => x.Date);
I would appreciate an answer in either Linq To Sql or just plain old SQL, thanks!
You should try a CROSS JOIN on the two reference tables, and then OUTER JOIN back to your 'data' table - and then check whether the Observation is null... then group and sum!
SELECT
[Name],
[Date],
SUM([Exists])
FROM
(
SELECT
name,
[Date],
CASE WHEN o.Id IS NULL THEN 0
ELSE 1
END as [Exists]
FROM
Rating r CROSS JOIN
Inspection i
LEFT OUTER JOIN Observation o
ON o.RatingId = r.Id AND o.InspectionId = i.Id
) as [source]
GROUP BY [Name], [Date]
ORDER BY
[Date],
name
Translating to LINQ would be a similar two-step process - get the inner result set (checking whether observation is NULL), before grouping and summing.

Left Join on Associative Table

I have three tables
Prospect -- holds prospect information
id
name
projectID
Sample data for Prospect
id | name | projectID
1 | p1 | 1
2 | p2 | 1
3 | p3 | 1
4 | p4 | 2
5 | p5 | 2
6 | p6 | 2
Conjoint -- holds conjoint information
id
title
projectID
Sample data
id | title | projectID
1 | color | 1
2 | size | 1
3 | qual | 1
4 | color | 2
5 | price | 2
6 | weight | 2
There is an associative table that holds the conjoint values for the prospects:
ConjointProspect
id
prospectID
conjointID
value
Sample Data
id | prospectID | conjointID | value
1 | 1 | 1 | 20
2 | 1 | 2 | 30
3 | 1 | 3 | 50
4 | 2 | 1 | 10
5 | 2 | 3 | 40
There are one or more prospects and one or more conjoints in their respective tables. A prospect may or may not have a value for each conjoint.
I'd like to have an SQL statement that will extract all conjoint values for each prospect of a given project, displaying NULL where there is no value for a value that is not present in the ConjointProspect table for a given conjoint and prospect.
Something along the lines of this for projectID = 1
prospectID | conjoint ID | value
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
2 | 1 | 10
2 | 2 | NULL
2 | 3 | 40
3 | 1 | NULL
3 | 2 | NULL
3 | 3 | NULL
I've tried using an inner join on the prospect and conjoint tables and then a left join on the ConjointProspect, but somewhere I'm getting a cartesian products for prospect/conjoint pairs that don't make any sense (to me)
SELECT p.id, p.name, c.id, c.title, cp.value
FROM prospect p
INNER JOIN conjoint c ON p.projectID = c.projectid
LEFT JOIN conjointProspect cp ON cp.prospectID = p.id
WHERE p.projectID = 2
ORDER BY p.id, c.id
prospectID | conjoint ID | value
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
2 | 1 | 10
2 | 2 | 40
2 | 1 | 10
2 | 2 | 40
2 | 1 | 10
2 | 2 | 40
3 | 1 | NULL
3 | 2 | NULL
3 | 3 | NULL
Guidance is very much appreciated!!
Then this will work for you... Prejoin a Cartesian against all prospects and elements within that project via a select as your first FROM table. Then, left join to the conjoinprospect. You can obviously change / eliminate certain columns from result, but at least all is there, in the join you want with exact results you are expecting...
SELECT
PJ.*,
CJP.Value
FROM
( SELECT
P.ID ProspectID,
P.Name,
P.ProjectID,
CJ.Title,
CJ.ID ConJointID
FROM
Prospect P,
ConJoint CJ
where
P.ProjectID = 1
AND P.ProjectID = CJ.ProjectID
ORDER BY
1, 4
) PJ
LEFT JOIN conjointProspect cjp
ON PJ.ProspectID = cjp.prospectID
AND PJ.ConjointID = cjp.conjointid
ORDER BY
PJ.ProspectID,
PJ.ConJointID
Your cartesian product is a result of joining by project Id - in your sample data there are 3 prospects with a project id of 1 and 3 conjoints with a project id of 1. Joining based on project id should then result in 9 rows of data, which is what you're getting. It looks like you really need to join via the conjointprospects table as that it what holds the mapping between prospects and conjoint.
What if you try something like:
SELECT p.id, p.name, c.id, c.title, cp.value
FROM prospect p
LEFT JOIN conjointProspect cp ON cp.prospectID = p.id
RIGHT JOIN conjoint c ON cp.conjointID = c.id
WHERE p.projectID = 2
ORDER BY p.id, c.id
Not sure if that will work, but it seems like conjointprospects needs to be at the center of your join in order to correctly map prospects to conjoints.