SQL Right Joins vs Left Joins - sql-server

Given that the total number of rows returned by this query below must equal the number of rows in the Invoices table
SELECT VendorName, InvoiceNumber
FROM Invoices
LEFT JOIN Vendors ON Invoices.VendorsID = Vendors.VendorID
Why doesn't the total number of rows returned by this query equal the number of rows in the Vendors table when you replace LEFT keyword with RIGHT keyword?

Your vendors table is the dependent table in a 1-to-Many relationship, so when you execute a RIGHT join on Invoices and Vendors, you will get 1 row for every Invoice + Vendor combination in the relationship, plus 1 row for every Vendor that does not have an invoice record in the Invoices table.
So, Let's say you have three vendors, and among them there are three invoices.
Vendor 1 has 2 invoices
Vendor 2 has 1 invoice
Vendor 3 has 0 invoices
With this data, a RIGHT JOIN will return 4 rows: two rows for Vendor 1, one row for Vendor 2, and 1 row for Vendor 3.
This fiddle provides an example of what I've described above.

The simple answer is because it would mean every record on the "right" side (in this case Vendors) would be represented in the results.
So if you have a vendor which does not have any invoices, it will show in the RIGHT JOIN, but will not show in the LEFT JOIN (because there is no match on the "left" side table).

The right join ensures that all the rows from the right table are present in the results.
But if there are 3 invoices for the same vendor than you still get 3 rows in the result set, not 1. That's how joins work :)

Related

LAG and/or LEAD alternative without window function in Pstgresql

Well I'm using Postgresql(but it won't matter if you can advise a solution in any SQL syntax), I have a table like
employee
department
salary
1
sales
30,000
2
sales
25,000
3
marketing
45,000
4
marketing
55,000
so on...
What I want to achieve is:
employee
department
salary
difference
1
sales
30,000
0/null
2
sales
25,000
5,000
3
marketing
45,000
0/null
4
marketing
55,000
10,000
So technically I want to extract the value difference of consecutive rows, however I can't use the window functions (I don't know why, but it is must to avoid in this challenge)
in a perfect world, we'd be able to do lag() or lead() functions partitioned by department name and store the value difference in other column, but I don't know how to do it without them.
I tried subqueries multiple ways, but every time I ended up having NULL or 0 in new a column
You can use a self-join to table itself and join each employee with the previous row within the same department.
SELECT t1.employee, t1.department, t1.salary, ABS(t2.salary - t1.salary) AS difference
FROM tab t1
LEFT JOIN tab t2
ON t1.department = t2.department AND t1.employee = t2.employee +1

Join with conditions

emphasized textI have 2 tables. First table have 3 columns namely SupplierId ,SupplierDetailID and entityid and second table has 2 column namely SupplierId and SupplierDetailID. In first table there are more than one combination of SUPPLIERID and Supplierdetailid due more than one entity id..I want to form left join on supplier Id field in such a way that only when suppliersDetailID is blank in first table it should take max value of SupplierDetailID from second tables for that particular SupplierId.
Formed query will give first_table.supplierID,if first_table SupplierDetailID is blank then max of second table SupplierDetailID for particular supplierId,first_table entityid.
enter image description here
This SQL Query will work for you.
SELECT s1.SupplierID,
ISNULL(s1.SupplierDetailID, MAX(s2.SupplierDetailID)) AS SupplierDetailID
FROM s1
LEFT JOIN s2
ON s1.SupplierID = s2.SupplierID
GROUP BY
s1.SupplierID,s1.SupplierDetailID;
s1 is first supplier table.
s2 is second supplier table.

SSRS how to deal with extra rows being created

I'm extremely new to SQL Server Reporting services and I'm wondering how I'm able to remove repeating rows.
The table is grouped by the Goal Name and Goal Description.
I would like to remove the rows that are circled or not have the row repeat.
The inner join on the Funding table is pulling 3 records and it is creating 3 rows under Acad Priority 1 and Acad Priority 2. How can I configure the table so it only displays the first row under both the priority columns. Thank you in advance.
SQL statement:
SELECT
Plan_Master.Date_Submitted, Plan_Master.Filename,
Plan_Master.Department, Plan_Master.Last_Name,
Plan_Master.First_Name, Plan_Master.Email,
Plan_Master.Mission_Statement,
Plan_Master.Vision_Statement, Plan_Master.Goals_Objectives,
Initiative_Master.Name, Initiative_Master.Description,
Initiative_Master.Acad_Priority_1, Initiative_Master.Acad_Priority_2,
Initiative_Master.Acad_Priority_3, Initiative_Master.Acad_Priority_4,
Initiative_Master.Acad_Priority_5, Initiative_Master.Acad_Priority_6,
Initiative_Master.Operational_Sustainability, Initiative_Master.People_Plan,
Funding.Beginning_Fiscal_Year
FROM
Plan_Master
INNER JOIN
Initiative_Master ON Plan_Master.Plan_ID = Initiative_Master.Plan_ID
INNER JOIN
Funding ON Initiative_Master.Initiative_ID = Funding.Initiative_ID
It looks like you need to delete your detail row group (=), leaving the values under the group that's grouped by Goal Name, Goal Description, Acad Priority 1, and Acad Priority 2. You should see it in the lower pane below the report design surface.

MSAccess/SQL lookup table for match field based on sum of current table.field

I've been battling this for the last week with many attempted solutions. I want to return the unique names in table with the sum of their points and their current dance level based on that sum. Ultimately I want compare the returned dance level with what is stored in the customer table against the customer and show only the records where the two dance levels are different (the stored dance level and the calculated dance level based on the current sum of the points.
The final solution will be a web page using ADODB connection to MSAccess DB (2013). But for starters just want it to work in MSAccess.
I have a MSAccess DB (2013) with the following tables.
PointsAllocation
CustomerID Points
100 2
101 1
102 1
100 1
101 4
DanceLevel
DLevel Threshold
Beginner 2
Intermediate 4
Advanced 6
Customer
CID Firstname Dancelevel1
100 Bob Beginner
101 Mary Beginner
102 Jacqui Beginner
I want to find the current DLevel for each customer by using the SUM of their Points in the first table. I have this first...
SELECT SUM(Points), CustomerID FROM PointsAllocation GROUP BY CustomerID
Works well and gives me total points per customer. I can then INNER JOIN this to the customer table to get the persons name. Perfect.
Now I want to add the DLevel from the DanceLevel table to the results where the SUM total is used to lookup the Threshold and not exceed the value so I get the following:
(1) (2) (3) (4)
Bob 3 Beginner Intermediate
Mary 5 Beginner Advanced
Where...
(1) Customer.Firstname
(2) SUM(PointsAllocation.Points)
(3) Customer.Dancelevel1
(4) Dancelevel.DLevel
Jacqui is not shown as her SUM of Points is less than or equal to 2 giving her a calculated dance level of Beginner and this already matches the her Dancelevel1 in the Customer table.
Any ideas anyone?
You can start from the customer table because you want to list every customer. Then left join it with a subquery that calculates the dance levels and point totals. The innermost subquery totals the points and then joins on valid dance levels and selects the max threshold value from the dance levels. Then left join on the DanceLevel table again on the threshold value to get the level's description.
Select Customer.Firstname,
CustomerDanceLevels.Points,
Customer.Dancelevel1,
Dancelevel.DLevel
from Customer
left join
(select CustomerID, Points, Min(Threshold) Threshold
from
(select CustomerID, sum(Points) Points
from PointsAllocation
group by CustomerID
) PointsTotal
left join DanceLevel
on PointsTotal.Points <= DanceLevel.Threshold
group by CustomerID, Points
) CustomerDanceLevels
on Customer.CID = CustomerDanceLevels.CustomerID
left join DanceLevel
on CustomerDanceLevels.Threshold = DanceLevel.Threshold

How to fetch an object graph at once?

I'm reading a book, where the author talks about fetching an row + all linked parent rows in one step. Like fetching an order + all it's items all at once. Okay, sounds nice, but really: I've never seen an possibility in SQL to ask for - lets say - one order + 100 items? How would this record set look like? Would I get 101 rows with merged fields of both the order and the item table, where 100 rows have a lot of NULL values for the order fields, while one row has a lot of NULL values for the item fields? Is that the way to go? Or is there something much cooler? I mean... I never heard of fetching arrays onto a field?
A simple JOIN would do the trick:
SELECT o.*
, i.*
FROM orders o
INNER JOIN order_items i
ON o.id = i.order_id
The will return one row for each row in order_items. The returned rows consist of all fields from the orders table, and concatenated to that, all fields from the order_items table (quite literally, the records from the tables are joined, that is, they are combined by record concatenation)
So if orders has (id, order_date, customer_id) and order_items has (order_id, product_id, price) the result of the statement above will consist of records with (id, order_date, customer_id, order_id, product_id, price)
One thing you need to be aware of is that this approach breaks down whenever there are two distinct 'detail' tables for one 'master'. Let me explain.
In the orders/order_items example, orders is the master and order_items is the detail: each row in order_items belongs to, or is dependent on exactly one row in orders. The reverse is not true: one row in the orders table can have zero or more related rows in the order_items table. The join condition
ON o.id = i.order_id
ensures that only related rows are combined and returned (leaving out the condition would retturn all possible combinations of rows from the two tables, assuming the database would allow you to omit the join condition)
Now, suppose you have one master with two details, for example, customers as master and customer_orders as detail1 and customer_phone_numbers. Suppose you want to retrieve a particular customer along with all is orders and all its phone numbers. You might be tempted to write:
SELECT c.*, o.*, p.*
FROM customers c
INNER JOIN customer_orders o
ON c.id = o.customer_id
INNER JOIN customer_phone_numbers p
ON c.id = p.customer_id
This is valid SQL, and it will execute (asuming the tables and column names are in place)
But the problem is, is that it will give you a rubbish result. Assuming you have on customer with two orders (1,2) and two phone numbers (A, B) you get these records:
customer-data | order 1 | phone A
customer-data | order 2 | phone A
customer-data | order 1 | phone B
customer-data | order 2 | phone B
This is rubbish, as it suggests there is some relationship between order 1 and phone numbers A and B and order 2 and phone numbers A and B.
What's worse is that these results can completely explode in numbers of records, much to the detriment of database performance.
So, JOIN is excellent to "flatten" a hierarchy of items of known depth (customer -> orders -> order_items) into one big table which only duplicates the master items for each detail item. But it is awful to extract a true graph of related items. This is a direct consequence of the way SQL is designed - it can only output normalized tables without repeating groups. This is way object relational mappers exist, to allow object definitions that can have multiple dependent collections of subordinate objects to be stored and retrieved from a relational database without losing your sanity as a programmer.
This is normally done through a JOIN clause. This will not result in many NULL values, but many repeated values for the parent row.
Another option, if your database and programming language support it, it to return both result sets in one connection - one select for the parent row another for the related rows.

Resources