Join tables on multiple conditions where rows may not have all IDs - sql

I need to build a query for a report that will return both budget and transaction data for all account types. The problem is that there are some account types present in the budget table that are not in the transaction table and vice versa. Here are the queries with the relevant information that needs to be joined from each table. First, the budget:
Select bp.ProjectID, bp.AccountCategoryID, bp. FiscalYearPeriod, bp.Amount AS BudgetAmount
from BudgetsProject bp
where bp.ProjectId = 1063 and bp.FiscalYearPeriod = 201510
The relevant data from the transaction table is found using:
SELECT f.ProjectKey, f.AccountCategoryKey, f.PostFiscalPeriodKey, sum(f.IncomeAmount) as IncomeAmount, sum(f.ExpenseAmount) as ExpenseAmount, sum(f.TransactionCount) as TransactionCount
FROM ActualCategoryPivotAccountTypeSubAccountFact f
Where f.ProjectKey = 1063 and f.PostFiscalPeriodKey = 201510
Group by f.ProjectKey, f.AccountCategoryKey, f.PostFiscalPeriodKey
The problem is that when I attempt to FULL JOIN the tables not every AccountCategoryKey value is in every row for both tables so I end up missing rows of data. I need to have every possible Accountcategory show in the result set and have NULLs where corresponding transaction or budget isn't available.
I know that this answer exists: What kind of join do I need to use to create one table from many?
but the tables must be joined on matching Project, AccountCategory, and FiscalYear fields and I'm not sure how to apply the solution presented there to a case where I need to be joining on multiple conditions.
EDIT: If this is helpful I've added logic to recreate tables here:
Create Table BudgetsReport (
AccountCategoryID int NOT NULL,
ProjectID int NOT NULL,
FiscalYearPeriod char(6) NOT NULL,
Amount numeric(10,2)
);
Create Table ActualCategoryPivotAccountTypeSubAccountFact (
PostFiscalPeriodKey int,
ProjectKey int,
AccountCategoryKey int,
IncomeAmount money,
ExpenseAmount money,
TransactionCount int
);
INSERT INTO BudgetsReport VALUES (1063, 5, 201510, 1626.00), (1063, 15, 201510, 8.00), (1063, 26, 201510, 1757.00), (1063, 36, 201510, 0.00), (1063, 38, 201510, 6508.00), (1063, 41, 201510, 115000.00), (1063, 42, 201510, 667.00), (1063, 43, 201510, 167.00), (1063, 51, 201510, 7289.00), (1063, 54, 201510, 21.00), (1063, 81, 201510, 138164.00), (1063, 87, 201510, 83.00), (1063, 88, 201510, 54.00), (1063, 90, 201510, 833.00);
INSERT INTO ActualCategoryPivotAccountTypeSubAccountFact VALUES (1063, 2, 201510, 0.00, 0.00, 214), (1063, 5, 201510, 0.00, 1004.42, 1), (1063, 15, 201510, 0.00, 3.92, 1), (1063, 26, 201510, 0.00, 1556.44, 10), (1063, 34, 201510, 0.00, 26.37, 1), (1063, 36, 201510, 0.00, 0.00, 19), (1063, 38, 201510, 0.00, 5764.65, 10), (1063, 41, 201510, 0.00, 131857.10, 29), (1063, 51, 201510, 0.00, 6456.27, 10), (1063, 54, 201510, 0.00, .44, 1), (1063, 87, 201510, 0.00, 28.30, 1), (1063, 90, 201510, 0.00, 545.96, 120), (1063, 93, 201510, 149945.01, 0.00, 213);

Having those predicates in your where clause (WHERE f.PostFiscalPeriodKey = 201510 and f.ProjectKey = 1063) are what's killing you, I think. You could move them to the on clause, but with a full join I don't know what that might end up with. Maybe try using a derived table with your constraints, and then join to that.
select
...
FROM
(
select *
from
ActualCategoryPivotAccountTypeSubAccountFact
where
PostFiscalPeriodKey = 201510
and ProjectKey = 1063) F
full join BudgetsProject bp
on f.PostFiscalPeriodKey = bp.FiscalYearPeriod
and bp.ProjectId = f.ProjectKey
and bp.AccountCategoryId = f.AccountCategoryKey
You could also try building a driver table with all the possible keys, and then outer joining to it. Not sure how this would perform though.

I suggest using a CTE and storing the possible account types and periods. Then left join to the actuals and budgets.
Another option would be to create a temp table with those values first then perform the select operation.

Related

Multiple Inserts in SQL Developer [duplicate]

This question already has answers here:
Best way to do multi-row insert in Oracle?
(9 answers)
Closed last year.
I tried to do below insert in SQL Developer
insert into tabletest values
(1, null, 23, 2020),
(2, null, 23, 2021),
(3, 77, 23, 2022),
(4, 77, 23, 2023),
(5, 77, 23, 2024),
(6, null, 23, 2025);
But it's giving me below error
Error report -
SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
Can someone tell me what's the error in the query please
For multiple inserts in the Oracle database, you can use one of these solutions
insert all
into tabletest values (1, null, 23, 2020)
into tabletest values (2, null, 23, 2021)
into tabletest values (3, 77, 23, 2022)
into tabletest values (4, 77, 23, 2023)
into tabletest values (5, 77, 23, 2024)
into tabletest values (6, null, 23, 2025)
select * from dual
;
or
insert into tabletest
select 1, null, 23, 2020 from dual union all
select 2, null, 23, 2021 from dual union all
select 3, 77, 23, 2022 from dual union all
select 4, 77, 23, 2023 from dual union all
select 5, 77, 23, 2024 from dual union all
select 6, null, 23, 2025 from dual
;

SQL command not properly ended - INSERT MULTIPLE ROWS - SQL

I donĀ“t know why SQL Developer returned "SQL command not properly ended" when i tried to add multiple rows. When i tried to insert one row, all was ok. Can somebody help me? Thanks.
INSERT INTO TEAMS (TEAM_ID, NAME, POSITION, PLAYED, WIN, LOSE, DRAW, GF, GA, GD, POINTS)
VALUES
('MUN','MANCHESTER UNITED', 2, 29, 16, 9, 4, 56, 32, 24, 57),
('LEI','LEICESTER CITY', 3, 29, 17, 5, 7, 53, 32, 21, 56),
('CHE','CHELSEA', 4, 29, 14, 9, 6, 44, 25, 19, 51); ```
Oracle require separate insert statements. VALUES can only be used for a single row. Alternatively, you can use INSERT . . . SELECT:
INSERT INTO TEAMS (TEAM_ID, NAME, POSITION, PLAYED, WIN, LOSE, DRAW, GF, GA, GD, POINTS)
SELECT 'MUN','MANCHESTER UNITED', 2, 29, 16, 9, 4, 56, 32, 24, 57 FROM DUAL UNION ALL
SELECT 'LEI','LEICESTER CITY', 3, 29, 17, 5, 7, 53, 32, 21, 56 FROM DUAL UNION ALL
SELECT 'CHE','CHELSEA', 4, 29, 14, 9, 6, 44, 25, 19, 51 FROM DUAL;

MS SQL Server 2012 - Insert Values if row does not exist

I'm new to SQL and I need to check whether or not values in a row exist before I insert them.
I am attempting to insert details to several rows at once.
The code I have is as follows:
insert into [Test].[Projects]([TestID], [GroupID], [TestingID], [Grade])
values
(314, 9, 77, 2)
,(314, 9, 77, 3)
,(314, 9, 77, 4)
,(329, 2, 65, 2)
,(329, 2, 65, 3)
,(329, 2, 65, 4)
go
If someone could help me to insert these where the row values do not exist then I would be very grateful
You could use the insert ... select syntax with a not exists condition that ensures that the very same record is not already there in the table:
insert into Test.Projects(TestID, GroupID, TestingID, Grade)
select v.*
from (values
(314, 9, 77, 2),
(314, 9, 77, 3),
(314, 9, 77, 4),
(329, 2, 65, 2),
(329, 2, 65, 3),
(329, 2, 65, 4)
) v(TestID, GroupID, TestingID, Grade)
where not exists (
select 1
from Test.Projects p
where
p.TestID = v.TestID
and p.GroupID = v.GroupID
and p.TestingID = v.TestingID
and p.Grade = v.Grade
)

SQL request error

Good evening everyone,
I'm working on a assignment and can't figure out the following, I have two tables:
CREATE TABLE Rental (
rental_id DECIMAL(12) PRIMARY KEY,
customer_id DECIMAL(12),
movie_id DECIMAL(12),
delivery_status VARCHAR(64),
return_status VARCHAR(64));
and
CREATE TABLE Movie (
movie_id DECIMAL(12) PRIMARY KEY,
DVD_id INTEGER NOT NULL,
title VARCHAR(64) NOT NULL,
stock_number DECIMAL(12),
director_id DECIMAL(12),
genre_id DECIMAL(12),
release_date DATE NOT NULL,
restrictions VARCHAR(256) NOT NULL);
I need to do the following, list the names of all movies that are currently unavailable, rented and not yet returned. And this is my query:
SELECT Movie.movie_id, Movie.title, Movie.stock_number
FROM Movie
WHERE (Movie.movie_id, Movie.stock_number) NOT IN (
SELECT Rental.movie_id,
COUNT(Rental.return_status) AS number_of_unreturned
FROM Rental
WHERE Rental.return_status = 'Unreturned'
GROUP BY Rental.movie_id
HAVING COUNT (Rental.return_status) > 1) AND Movie.stock_number = 0;
I definitely have movies in Movie table that are not "Unreturend" but I get no rows selected all the time. Any advices or directions to think would be appreciated. Thanks!
I edited this post and added the content of the tables.
INSERT INTO Movie VALUES (1, 1, 'Amblin', 1, 1, 1, CAST('18-Dec-1968' AS DATE), 'G');
INSERT INTO Movie VALUES (2, 2, 'Duel', 2, 1, 2, CAST('13-Nov-1971' AS DATE), 'R');
INSERT INTO Movie VALUES (3, 3, 'Something Evil ', 3, 1, 3, CAST('21-Jan-1972' AS DATE), 'R');
INSERT INTO Movie VALUES (4, 4, 'The Sugarland Express ', 4, 1, 4, CAST('05-Apr-1974' AS DATE), 'PG13');
INSERT INTO Movie VALUES (5, 5, 'Jaws', 5, 1, 3, CAST('20-Jun-1975' AS DATE), 'R');
INSERT INTO Movie VALUES (6, 6, 'Close Encounters of the Third Kind', 6, 1, 5, CAST('16-Nov-1977' AS DATE), 'PG13');
INSERT INTO Movie VALUES (7, 7, ' 1941', 7, 1, 6, CAST('14-Dec-1979' AS DATE), 'G');
INSERT INTO Movie VALUES (8, 8, 'Raiders of the Lost Ark', 8, 1, 7, CAST('12-Jun-1981' AS DATE), 'PG13');
INSERT INTO Movie VALUES (9, 9, 'E.T. the Extra-Terrestrial', 9, 1, 5, CAST('11-Jun-1982' AS DATE), 'PG13');
INSERT INTO Movie VALUES (10, 10, 'Twilight Zone: The Movie', 10, 1, 3, CAST('24-Jun-1983' AS DATE), 'R');
INSERT INTO Movie VALUES (11, 11, 'Indiana Jones and the Temple of Doom', 11, 1, 7, CAST('23-May-1984' AS DATE), 'PG13');
INSERT INTO Movie VALUES (12, 12, 'The Color Purple', 12, 1, 4, CAST('18-Dec-1985' AS DATE), 'G');
INSERT INTO Movie VALUES (13, 13, 'Empire of the Sun', 13, 1, 4, CAST('25-Dec-1987' AS DATE), 'G');
INSERT INTO Movie VALUES (14, 14, 'Always', 14, 1, 4, CAST('22-Dec-1989' AS DATE), 'G');
INSERT INTO Movie VALUES (15, 15, 'Indiana Jones and the Last Crusade', 15, 1, 7, CAST('24-May-1989' AS DATE), 'G');
INSERT INTO Movie VALUES (16, 16, 'Hook', 16, 1, 8, CAST('11-Dec-1991' AS DATE), 'G');
INSERT INTO Movie VALUES (17, 17, 'Jurassic Park ', 17, 1, 5, CAST('11-Jun-1993' AS DATE), 'PG13');
INSERT INTO Movie VALUES (18, 18, 'Schindler''s List', 18, 1, 4, CAST('15-Dec-1993' AS DATE), 'PG13');
INSERT INTO Movie VALUES (19, 19, 'The Lost World: Jurassic Park', 19, 1, 5, CAST('23-May-1997' AS DATE), 'PG13');
INSERT INTO Movie VALUES (20, 20, 'Amistad', 20, 1, 4, CAST('10-Dec-1997' AS DATE), 'PG13');
INSERT INTO Movie VALUES (21, 21, 'Saving Private Ryan', 21, 1, 4, CAST('24-Jul-1998' AS DATE), 'PG13');
INSERT INTO Movie VALUES (22, 22, 'A.I. Artificial Intelligence', 22, 1, 4, CAST('29-Jun-2001' AS DATE), 'PG13');
INSERT INTO Movie VALUES (23, 23, 'Minority Report', 23, 1, 7, CAST('21-Jun-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (24, 24, 'Catch Me If You Can', 24, 1, 8, CAST('25-Dec-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (25, 25, ' The Terminal', 25, 1, 4, CAST('18-Jun-2004' AS DATE), 'G');
INSERT INTO Movie VALUES (26, 26, 'War of the Worlds', 26, 1, 5, CAST('29-Jun-2005' AS DATE), 'PG13');
INSERT INTO Movie VALUES (27, 27, 'Munich', 27, 1, 4, CAST('23-Dec-2005' AS DATE), 'PG13');
INSERT INTO Movie VALUES (28, 28, 'Indiana Jones and the Kingdom of the Crystal Skull', 28, 1, 7, CAST('22-May-2008' AS DATE), 'PG13');
INSERT INTO Movie VALUES (29, 29, 'The Adventures of Tintin', 28, 1, 7, CAST('21-Dec-2011' AS DATE), 'PG13');
INSERT INTO Movie VALUES (30, 30, 'War Horse', 30, 1, 4, CAST('25-Dec-2011' AS DATE), 'PG13');
INSERT INTO Movie VALUES (31, 31, 'Lincoln', 31, 1, 4, CAST('09-Nov-2012' AS DATE), 'PG13');
INSERT INTO Movie VALUES (32, 32, 'Bridge of Spies', 32, 1, 4, CAST('16-Oct-2015' AS DATE), 'PG13');
INSERT INTO Movie VALUES (33, 33, 'The BFG', 33, 1, 8, CAST('01-Jul-2016' AS DATE), 'PG13');
INSERT INTO Movie VALUES (34, 34, 'Praying with Anger', 34, 2, 5, CAST('12-Sep-1992' AS DATE), 'PG13');
INSERT INTO Movie VALUES (35, 35, 'Wide Awake', 35, 2, 4, CAST('20-Mar-1998' AS DATE), 'G');
INSERT INTO Movie VALUES (36, 36, 'The Sixth Sense', 36, 2, 2, CAST('06-Aug-1999' AS DATE), 'PG13');
INSERT INTO Movie VALUES (37, 37, 'Unbreakable', 37, 2, 2, CAST('22-Nov-2000' AS DATE), 'PG13');
INSERT INTO Movie VALUES (38, 38, 'Signs', 38, 2, 2, CAST('02-Aug-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (39, 39, 'The Village', 39, 2, 2, CAST('30-Jul-2004' AS DATE), 'PG13');
INSERT INTO Movie VALUES (40, 40, 'Lady in the Water', 40, 2, 8, CAST('21-Jul-2006' AS DATE), 'PG13');
INSERT INTO Movie VALUES (41, 41, 'The Happening', 41, 2, 2, CAST('13-Jun-2008' AS DATE), 'R');
INSERT INTO Movie VALUES (42, 42, 'The Last Airbender', 42, 2, 7, CAST('02-Jul-2010' AS DATE), 'G');
INSERT INTO Movie VALUES (43, 43, 'After Earth', 43, 2, 7, CAST('31-May-2013' AS DATE), 'G');
INSERT INTO Movie VALUES (44, 44, 'The Visit', 44, 2, 3, CAST('11-Sep-2015' AS DATE), 'R');
INSERT INTO Movie VALUES (45, 45, 'Split', 45, 2, 2, CAST('20-Jan-2017' AS DATE), 'PG13');
and
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 1, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 3, 6, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 4, 7, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 37, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 24, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 3, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 13, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 8, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 3, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 3, 27, 'Delivered', 'Returned');
Sorry if that is a too long post.
I don't want to write the code since you are a student. I'll give some direction though. In your where clause you're comparing (movie.movie_id = rental.movie_id) and (movie.stock_number = count(rental.return_status). Comparing the stock_number to the count of returns is incorrect.
When returning columns from multiple tables, use a join. The in statement does a comparison. Count is not being returned.
Join movies and the "in" subquery on movie_id. Create an alias on the subquery so you can join it.
Add the count column to the topmost outer select
Please try, if this logic is correct, I did not quite understand column naming. You might change last row (having) to correct it.
SELECT
m.movie_id, m.title, m.stock_number -- Getting movie id, movie title, stock number
FROM Movie m -- from movie table
JOIN rental r
ON (m.movie_id = r.movie_id) -- joining rental table in movie_id
WHERE
r.return_status = 'Unreturned' -- where return_status is unreturned
GROUP BY
m.movie_id, m.title, m.stock_number -- grouping_by (same as select)
HAVING
SUM(r.movie_id) > m.stock_number; -- restricting group by quantity
To resolve the query try first to break it down in the components you need.
In this case you need to compare the number of rented movies against the stock of movies.
So write 2 separte queries:
1 - One that will provide the movie id and the number to movies in stock.
2 - Another for the movie id and the number of rentals. For this one you have to count the unretured.
After you have the two queries, you can use them as subqueries of a higer level query that treats each or these queries as a table joined by the common id field.
And add awhere clause comparing the stock with the counted field.
Example:
Table A: id, name, age
Table B: table_b_id, table_a_id, telephone, address
Query 1: select id, name, age from A
Query 2: select table_a_id, telephone, address from B
select Q1.id, Q1.name, Q1.age, Q2telephone, Q2.address
from
(select A.id, A.name, A.age from A) Q1,
(select B.table_a_id, B.telephone, B.address from B) Q2
where
Q1.id = Q2.table_a_id

TSQL: How to add a totals row

I'm on SQL Server 2014 and I have a list of building ID's with various totals columns. I would like to add a row of totals for the building.
Can the following desired output be done in SQL? If so, what's the best way? I need to learn how to this for various projects. I don't need LevelID totals, just for the other columns, and I'm not sure if we can add the text 'BuildingTotal' in the totals row.
Desired Output:
SQL Fiddle:
Here is the code for a test table in case SQL Fiddle doesn't work.
CREATE TABLE EMPLOYEES
(
BuildingID Numeric,
LevelID Numeric,
FemaleEmp Numeric,
MaleEmp Numeric,
TotalEmpByLevel Numeric
)
INSERT INTO EMPLOYEES
(BuildingID, LevelID, FemaleEmp, MaleEmp, TotalEmpByLevel)
VALUES
(111, 1,91, 89, 180),
(111, 2,98, 94, 192),
(111, 3,94, 113 , 207),
(111, 4,110, 119, 229),
(111, 5,107, 9, 203),
(113, 1,53, 4, 101),
(113, 2,51, 5, 106),
(113, 3,68, 5, 119),
(113, 4,58, 6, 118),
(113, 5,57, 6, 117),
(114, 1,25, 3, 56 ),
(114, 2,26, 3, 63 ),
(114, 3,32, 2, 61 ),
(114, 4,27, 3, 58 ),
(114, 5,26, 2, 49 ),
(116, 1,84, 102 , 186),
(116, 2,83, 92, 175),
(116, 3,89, 87, 176),
(116, 4,71, 91, 162),
(116, 5,87, 72, 159)
Thank you for your help!
One method is to use grouping sets or with rollup. This requires a little trick, though. You need an aggregation query:
select BuildingId, LevelId, sum(FemaleEmp) as FemaleEmp,
sum(MaleEmp) as MaleEmp, sum(TotalEmpByLevel) as TotalEmpByLevel
from employees
group by grouping sets((BuildingId, LevelId), (BuildingId));
You can add the word Total to the lines. This is a bit tricky, because the types are different:
select (case when grouping(LevelId) = 1 then 'Building Total' else cast(BuildingId as varchar(255)) end) as BuildingId,
LevelId, sum(FemaleEmp) as FemaleEmp,
sum(MaleEmp) as MaleEmp, sum(TotalEmpByLevel) as TotalEmpByLevel
from employees
group by grouping sets((BuildingId, LevelId), (BuildingId));
Try Group by with rollup
This is link with example