SQL How to convert this to a SubQuery? - sql

Learning, be kind.
I am trying to understand how this works and I have done several successful conversions, but this one I am stumped on.
How do I take this code and convert it to a subquery? I'm a little lost.
SELECT o.FirstName + ' ' + o.LastName AS Driver, COUNT(DISTINCT s.vehicleID) NoOfBusesUsed
FROM Operators AS o, Runs AS r, Schedules AS s JOIN Trips AS t
ON s.scheduleID = t.scheduleID
WHERE r.BidDate BETWEEN '09/01/2004' AND '09/30/2004'
GROUP BY o.FirstName + ' ' + o.LastName
HAVING COUNT(s.vehicleID) > 1
Here is how my tables are setup. If more info is needed, I can post.
CREATE TABLE Operators
(
SeniorityNumber char(4) NOT NULL
CONSTRAINT ck_Operators_Seniority
CHECK (SeniorityNumber LIKE '[0-9][0-9][0-9][0-9]'),
FirstName varchar(25) NOT NULL,
LastName varchar(35) NOT NULL,
HireDate smalldatetime
CONSTRAINT ck_Operators_HireDate CHECK (HireDate <=Getdate())
)
CREATE TABLE Trips
(
RouteNumber varchar(4) NOT NULL,
StartLocation varchar(50) NOT NULL,
StartTime time NOT NULL,
EndLocation varchar(50) NOT NULL,
EndTime time NOT NULL,
EffectiveDate smalldatetime NOT NULL
CHECK (EffectiveDate >= cast('1/1/2000' as smalldatetime)),
CONSTRAINT ck_Trips_StartEnd CHECK (EndTime > StartTime)
)
CREATE TABLE Vehicles
(
Manufacturer varchar(50)
DEFAULT 'Gillig',
Model varchar(50),
ModelYear int
DEFAULT DatePart(yyyy,GetDate())
CHECK (ModelYear <= DatePart(yyyy,GetDate())),
PurchaseDate smalldatetime
)
GO
ALTER TABLE operators
ADD OperatorID int IDENTITY --Primary Key
GO
ALTER TABLE Operators
ADD CONSTRAINT pkOperators Primary key (OperatorID)
ALTER TABLE Vehicles
ADD VehicleID int IDENTITY Primary Key
ALTER TABLE Trips
ADD TripID int IDENTITY Primary key
GO
CREATE TABLE Runs
(
RunID int IDENTITY NOT NULL Primary Key,
OperatorID int NOT NULL REFERENCES Operators,
BidDate date NOT NULL
CONSTRAINT ckRunBidDate CHECK
(biddate <= dateadd(mm,6,getdate())) --getdate() + 180
)
GO
CREATE TABLE Schedules
(
ScheduleID int IDENTITY Primary Key,
RunID int NOT NULL,
VehicleID int NOT NULL,
CONSTRAINT fk_Schedules_Runs FOREIGN KEY (RunID)
REFERENCES Runs(RunID),
CONSTRAINT fk_Schedules_Vehicles FOREIGN KEY (VehicleID)
REFERENCES Vehicles
)
ALTER TABLE Trips
ADD ScheduleID int NULL REFERENCES Schedules

When you want to use a query as a sub-query you can use WITH statement or a derived table like:
With:
;WITH subQuery AS (
/* Your query here */
)
SELECT *
FROM subQuery
Derived table
SELECT *
FROM (
/* your query here */
) As subQuery
I think you should use a query like this:
SELECT
o.FirstName + ' ' + o.LastName AS Driver,
DT.cnt AS NoOfBusesUsed
FROM
Operators AS o
JOIN
(SELECT
r.OperatorID,
COUNT(DISTINCT s.VehicleID) AS cnt
FROM
Schedules s
JOIN
Runs r ON s.RunID = r.RunID
) AS DT
ON DT.OperatorID = o.OperatorID
WHERE
ISNULL(DT.cnt, 0) > 1

Related

DateDiff asc and desc

SELECT DISTINCT
at.AccountId AS AccountId,
a.FirstName + ' ' + a.LastName AS [FullName],
DATEDIFF(day, T.ArrivalDate, T.ReturnDate) AS LongestTrip,
DATEDIFF(day, T.ArrivalDate, T.ReturnDate) AS ShortestTrip
FROM
Accounts a
JOIN
AccountsTrips at ON a.Id = AT.AccountId
JOIN
Trips t ON T.Id = AT.TripId
WHERE
a.MiddleName IS NULL AND t.CancelDate IS NULL
ORDER BY
DATEDIFF(day, T.ArrivalDate, T.ReturnDate) DESC, ShortestTrip ASC
The code only orders the tables descending in LongestTrip and in ShortestTrip
SAMPLE DATA !
Find the longest and shortest trip for each account, in days. Filter the results to accounts with no middle name and trips, which are not cancelled (CancelDate is null).
Order the results by Longest Trip days (descending), then by Shortest Trip (ascending).
Examples
AccountId FullName LongestTrip ShortestTrip
------------------------------------------------------------
40 Winna Maisey 7 1
56 Tillie Windress 7 1
57 Eadith Gull 7 1
66 Sargent Rockhall 7 1
69 Jerome Flory 7 2
… … … …
The Tables are --
CREATE TABLE Cities
(
Id INT PRIMARY KEY IDENTITY,
Name NVARCHAR(20) NOT NULL,
CountryCode CHAR(2) NOT NULL
)
CREATE TABLE Hotels
(
Id INT PRIMARY KEY IDENTITY,
Name NVARCHAR(30) NOT NULL,
CityId INT FOREIGN KEY REFERENCES Cities(Id) NOT NULL,
EmployeeCount INT NOT NULL,
BaseRate DECIMAL(10,2)
)
CREATE TABLE Rooms
(
Id INT PRIMARY KEY IDENTITY,
Price DECIMAL(10,2) NOT NULL,
Type NVARCHAR(20) NOT NULL,
Beds INT NOT NULL,
HotelId INT FOREIGN KEY REFERENCES Hotels(Id) NOT NULL
)
CREATE TABLE Trips
(
Id INT PRIMARY KEY IDENTITY,
RoomId INT FOREIGN KEY REFERENCES Rooms(Id) NOT NULL,
BookDate DATE NOT NULL, CHECK(BookDate<ArrivalDate),
ArrivalDate DATE NOT NULL, CHECK(ArrivalDate<ReturnDate),
ReturnDate DATE NOT NULL,
CancelDate DATE
)
CREATE TABLE Accounts
(
Id INT PRIMARY KEY IDENTITY,
FirstName NVARCHAR(50) NOT NULL,
MiddleName NVARCHAR(20),
LastName NVARCHAR(50) NOT NULL,
CityId INT NOT NULL,
BirthDate DATE NOT NULL,
Email VARCHAR(100) UNIQUE NOT NULL
CONSTRAINT FK_CityId FOREIGN KEY (CityId)
REFERENCES Cities(Id)
)
CREATE TABLE AccountsTrips
(
AccountId INT FOREIGN KEY REFERENCES Accounts(Id) NOT NULL,
TripId INT FOREIGN KEY REFERENCES Trips(Id) NOT NULL,
Luggage INT NOT NULL, CHECK(Luggage >= 0)
)
You want to pick the longest and shortest trips per account from your data. As all you want to get from the trips is the duration, you can simply aggregate and show MIN and MAX duration:
SELECT
a.Id AS AccountId,
a.FirstName + ' ' + a.LastName AS [FullName],
MIN(DATEDIFF(day, T.ArrivalDate, T.ReturnDate)) AS LongestTrip,
MAXD(ATEDIFF(day, T.ArrivalDate, T.ReturnDate)) AS ShortestTrip
FROM
Accounts a
JOIN
AccountsTrips at ON a.Id = AT.AccountId
JOIN
Trips t ON T.Id = AT.TripId
WHERE
a.MiddleName IS NULL AND t.CancelDate IS NULL
GROUP BY
a.Id, a.FirstName, a.LastName
ORDER BY
LongestTrip DESC, ShortestTrip ASC;
If you wanted to show additional data from the trips, you would use window functions (probably MIN OVER and MAX OVER) and would then either show two rows per account or aggregate these two rows.

Get count of games and display the players who played half of games

i Need help in these tables, i want SQL statement to give me this :
the players who played in half or more of the games, lets assume that we have 6 different games in 'GameType' table ... So I want to display all players who played 3 or more games.
like :
ID surName number of games played
1 test1 3
2 test2 4
3 test3 3
4 test4 6
this what i done until now:
SELECT dbo.Player.ID, dbo.Player.surName, count(DISTINCT
dbo.PlayerInAGame.gameTypeName) AS games_played, count(DISTINCT
dbo.Game.gameTypeName) AS games_count
FROM dbo.Player INNER JOIN
dbo.PlayerInAGame ON dbo.Player.ID =
dbo.PlayerInAGame.playerID INNER JOIN
dbo.Game ON dbo.PlayerInAGame.gameTypeName = dbo.Game.gameTypeName AND
dbo.PlayerInAGame.gameDateTime = dbo.Game.gameStartDateTime
GROUP BY dbo.Player.ID, dbo.Player.surName, dbo.Game.DealerInGame
here is the tables:
create table Dealer
(
number int identity(1000,1) primary key,
firstName nvarchar(20) not null,
surName nvarchar(20) not null,
birthDate date not null,
startWorkingDate date not null,
ID char(9) check(ID like replicate('[0-9]',9)) not null unique,
check(datediff(year,birthDate,startWorkingDate)>=24)
)
create table GameType
(
name nvarchar(20) primary key,
description nvarchar(20) not null,
minimumPlayers tinyint check (minimumPlayers > 0) not null,
maximumPlayers tinyint check (maximumPlayers > 0) not null,
check(minimumPlayers <= maximumPlayers)
)
create table Game
(
gameTypeName nvarchar(20) references GameType(name) on delete cascade,
gameStartDateTime datetime,
gameEndTime time,
DealerInGame int not null references Dealer(number),
primary key(gameTypeName,gameStartDateTime)
)
create table Player
(
ID char(9) primary key,
firstName nvarchar(20) not null,
surName nvarchar(20) not null,
city nvarchar(20) not null,
birthDate date check(datediff(year,birthDate,getdate())>=18) not null,
preferred nvarchar(20) references GameType(name) on delete set null
)
create table PlayerInAGame
(
playerID char(9) references Player(ID),
gameTypeName nvarchar(20),
gameDateTime datetime,
betAmount int check(betAmount>0) not null,
winLosAmount int,
check((winLosAmount = -betAmount) or (winLosAmount>=betAmount)),
foreign key(gameTypeName,gameDateTime) references
Game(gameTypeName,gameStartDateTime), primary
key(playerID,gameTypeName,gameDateTime) )
create table PlayerDealerRelation
(
dealerNumber int references Dealer(number) on delete cascade,
playerID char(9) references Player(ID),
relationType char(1) check(relationType in ('P','G','B','C','U','N')),
primary key(dealerNumber,playerID)
)
If your query in the question gives you the correct count, then it is very easy to add an extra filter that would leave only those rows where games_played is more than half of games_count.
Just add HAVING:
SELECT
dbo.Player.ID,
dbo.Player.surName,
count(DISTINCT dbo.PlayerInAGame.gameTypeName) AS games_played,
count(DISTINCT dbo.Game.gameTypeName) AS games_count
FROM
dbo.Player
INNER JOIN dbo.PlayerInAGame ON dbo.Player.ID = dbo.PlayerInAGame.playerID
INNER JOIN dbo.Game
ON dbo.PlayerInAGame.gameTypeName = dbo.Game.gameTypeName
AND dbo.PlayerInAGame.gameDateTime = dbo.Game.gameStartDateTime
GROUP BY dbo.Player.ID, dbo.Player.surName, dbo.Game.DealerInGame
HAVING
count(DISTINCT dbo.PlayerInAGame.gameTypeName) >
count(DISTINCT dbo.Game.gameTypeName) / 2

SQL Server 2012 : Create Table

CREATE TABLE Schedule
(
Section DATETIME NOT NULL PRIMARY KEY(CourseID, Section, EmployeeID),
CourseID VARCHAR(10) REFERENCES Course(CourseID) NOT NULL,
EmployeeID VARCHAR(20) NOT NULL REFERENCES Employee(EmployeeID),
StartTime TIME NULL,
Days DATE NULL,
Length TIME NULL
)
CREATE TABLE Enrollment
(
StudentID INT Primary key (StudentID, CourseID, Section) NOT NULL,
CourseID VARCHAR(10) REFERENCES Course(CourseID) NOT NULL,
Section DATETIME NOT NULL REFERENCES Schedule(Section)
)
2nd table did not get created, where did I go wrong?
Its because you made the primary key in the Schedule table a natural/combined key.
Try creating a stand alone column for this purpose instead. I've included an example below that shows the differences.
CREATE TABLE DBO.PK_TEST (
Col_A INT NOT NULL
,Col_B INT NOT NULL
,Primary Key(Col_A,Col_B)
)
Create table DBO.PK_TEST_2 (
Col_A int NOT NULL
,Col_B int NOT NULL
,Col_C as (cast(Col_A as nvarchar)
+ cast(Col_B as nvarchar)) PERSISTED NOT NULL
,primary key(Col_C)
)

INSERT Conflict on Virtual Table SQL

I am having a problem on the INSERT because of a FK reference. The process goes like this:
I create the table Cuentas, and Cuentas_Con_RowNumber
I select from a huge table with over 3 million records. Because some are repeated and I need to store only 1 "cuenta", I made the tempDB. I have to do this, because on the huge db there are many records with the same Cuenta_Nro with different transactions, and I just need one.
I select from the tempDB all the columns but the RowNumber and then insert it into the Cuentas table.
The problem is that the tempDB Pais (country) column is not a FK which references to the Paises (countries) table, and on the original table (Cuentas) it does, therefore, it crashes.
Code:
CREATE TABLE Paises
(
Pais_Id numeric(18,0) PRIMARY KEY NOT NULL,
Pais_Nombre varchar(255) NOT NULL
)
CREATE TABLE Cuentas
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_Moneda varchar(255) DEFAULT 'Dolar',
Cuenta_Tipo numeric(18,0)
FOREIGN KEY REFERENCES Tipo_De_Cuentas(Tipo_De_Cuenta_Id),
Cuenta_PaisOrigen numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_PaisAsignado numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Tarjeta numeric(18, 0)
FOREIGN KEY REFERENCES Tarjetas(Tarjeta_Nro),
Cuenta_Cliente numeric(18, 0)
FOREIGN KEY REFERENCES Clientes(Cliente_Id)
)
CREATE TABLE #Cuentas_Con_RowNumer
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_PaisOrigen numeric(18,0)),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Cliente numeric(18,0),
Cuenta_Tarjeta numeric(18,0),
RowNumber int
)
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
Maestro.Cuenta_Numero, Maestro.Cuenta_Estado, Maestro.Cuenta_Pais_Codigo,
Maestro.Cuenta_Fecha_Creacion, Maestro.Cuenta_Fecha_Cierre, Clientes.Cliente_Id, Maestro.Tarjeta_Numero,
ROW_NUMBER() OVER (PARTITION BY Maestro.Cuenta_Numero ORDER BY Maestro.Cuenta_Numero) AS RowNumber
FROM gd_esquema.Maestra Maestro, dbo.Clientes
WHERE
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre) AS a
WHERE a.RowNumber = '1'
INSERT INTO Cuentas
(
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
)
SELECT
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
FROM #Cuentas_Con_RowNumer
The error message is:
Instrucción INSERT en conflicto con la restricción FOREIGN KEY "FK__Cuentas__Cuenta___24B338F0". El conflicto ha aparecido en la base de datos "GD1C2015", tabla "dbo.Paises", column 'Pais_Id'.
The issue is because Maestro.Cuenta_Pais_Codigo column is being pulled from gd_esquema.Maestra table which in turn is going as Cuenta_PaisOrigen in target table and has a foreign key defined.
There will be some records which are being selected for insert Cuentas table that doesn't have a matching Pais_Id record in dbo.Paises table.
You can add a inner join as below and check the results as :
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
...
FROM gd_esquema.Maestra Maestro
inner join dbo.Clientes on
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre
inner join Paises P on Maestro.Cuenta_Pais_Codigo = P.Pais_Id
) AS a
WHERE a.RowNumber = '1'

SQL Logic and Aggregate Issue

I have the following problem to solve in SQL :
d) A query that provides management information on take up of the various types of activities on offer. For each type of activity, the query should show the total number of individuals who took that type of activity and the average number of individuals taking each type of activity.
Here are my tables :
CREATE TABLE accommodations
(
chalet_number int PRIMARY KEY,
chalet_name varchar(40) NOT NULL,
no_it_sleeps number(2) NOT NULL,
indivppw number(4) NOT NULL
)
CREATE TABLE supervisors
(
supervisor_number int PRIMARY KEY,
supervisor_forename varchar(30) NOT NULL,
supervisor_surname varchar(30) NOT NULL,
mobile_number varchar(11) NOT NULL
)
CREATE TABLE visitors
(
visitor_ID int PRIMARY KEY,
group_ID int NOT NULL,
forename varchar(20) NOT NULL,
surname varchar(20) NOT NULL,
dob date NOT NULL,
gender varchar(1) NOT NULL
)
CREATE TABLE activities
(
activity_code varchar(10) PRIMARY KEY,
activity_title varchar(20) NOT NULL,
"type" varchar(20) NOT NULL
)
CREATE TABLE "groups"
(
group_ID int PRIMARY KEY,
group_leader varchar(20) NOT NULL,
group_name varchar(30)
number_in_group number(2) NOT NULL
)
CREATE TABLE bookings
(
group_ID int NOT NULL,
start_date date NOT NULL,
chalet_number int NOT NULL,
no_in_chalet number(2) NOT NULL,
start_date date NOT NULL,
end_date date NOT NULL,
CONSTRAINT bookings_pk PRIMARY KEY(group_ID, chalet_number));
CREATE TABLE schedule
(
schedule_ID int PRIMARY KEY,
activity_code varchar(10) NOT NULL,
time_of_activity number(4,2) NOT NULL,
am_pm varchar(2) NOT NULL,
"date" date NOT NULL
)
CREATE TABLE activity_bookings
(
visitor_ID int NOT NULL,
schedule_ID int NOT NULL,
supervisor_number int NOT NULL,
comments varchar(200),
CONSTRAINT event_booking_pk PRIMARY KEY(visitor_ID, schedule_ID));
ALTER TABLE visitors
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE Schedule
ADD FOREIGN KEY (activity_code)
REFERENCES activities(activity_code)
ALTER TABLE bookings
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE bookings
ADD FOREIGN KEY (chalet_number)
REFERENCES accommodations(chalet_number)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (visitor_ID)
REFERENCES visitors(visitor_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (schedule_ID)
REFERENCES schedule(schedule_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (supervisor_number)
REFERENCES supervisors(supervisor_number)
I have the following solution:
SELECT activities."type", 'overalltotal' AS OT, ('overalltotal' / 'activities') AS AVG
FROM activities, schedule
WHERE 'overalltotal' = (SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type"
)
AND 'activities' = (SELECT COUNT(DISTINCT activities."type")
FROM activities
)
AND schedule.activity_code = activities.activity_code
GROUP BY activities."type";
I have implemented sample data and code to check the variables above:
SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type";
Result : 20
SELECT COUNT(DISTINCT activities."type")
FROM activities;
Result : 5
However when running the code :
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause:
*Action:
EDIT:
Using Dave's Code i have the following output:
Snowboarding 15
sledding 19
Snowmobiling 6
Ice Skating 5
Skiing 24
How would i do the final part of the question?
and the average number of individuals taking each type of activity.
You must use double quotes around column names in Oracle, not single quotes. For example, "overalltotal". Single quotes are for text strings, which is why you're getting an invalid number error.
EDIT: This is probably the type of query you want to use:
SELECT activities."type", COUNT(*) AS total, COUNT(*)/(COUNT(*) OVER ()) AS "avg"
FROM activities a
JOIN schedule s ON a.activity_code=s.activity_code
JOIN activity_bookings ab ON s.schedule_ID=ab.schedule_ID
GROUP BY activities."type";
Basically, because each activity booking has one visitor id, we want to get all the activity bookings for each activity. We have to go through schedule to do that. They we group the rows by the activity type and count how many activity bookings we have for each type.