Query to show specific values from related tables - sql

In my case i have three tables. The Contracts table, the agreements table and the payments table. What i have is a table with contracts which represents the value in debt, another table with the agreements of the conditions to pay off the debt, and another table related to the agreements table who has the debt split in parcels.
ContractsTable
(Id | Number | Name | Debt | ...)
1 | 1234 | AAAAAA | 1250,00 € | ...
2 | 1235 | BBBBBB | 5000,20 € | ...
3 | 1236 | CCCCCC | 500,00 € | ...
AgreementsTable
(Id | ContractId | Debt | IsValid | ...)
1 | 1 | 1250,00 € | 1 | ...
2 | 2 | 5000,20 € | 0 | ...
3 | 2 | 5000,20 € | 1 | ...
4 | 3 | 500,00 € | 0 | ...
PaymentsTable
(Id | AgreementId | Date | Amount | IsPaid | ...)
1 | 1 | 01/08/2012 | 500,00 € | 1 | ...
2 | 1 | 01/09/2012 | 500,00 € | 1 | ... -> Last payment
3 | 1 | 01/10/2012 | 250,00 € | 0 | ... -> Next Payment
4 | 3 | 01/08/2012 | 1000,00 € | 1 | ...
5 | 3 | 01/09/2012 | 1000,00 € | 1 | ...
6 | 3 | 01/10/2012 | 1000,00 € | 0 | ...
7 | 3 | 01/11/2012 | 1000,00 € | 0 | ...
8 | 3 | 01/12/2012 | 1000,20 € | 0 | ...
So when i execute the stored procedure to get the table with the contracts, i want to somehow see a column with the date of last payment that was done and the date of next payment to be done too. But i will only be able to see the date of the last payment done and the date of the next payment to be done if the contract has a valid agreement related with and in the case of the next payment only if the agreement is valid.
I am working with MS Sql Server.
Thanks in advance!

Will this work for you?
select aa.Id
, aa.Number
, aa.Name
, aa.Debt
...
, max(aa.Date_LastPayment) as Date_LastPayment
, min(aa.Date_NextPayment) as Date_NextPayment
from
(
select a.Id
, a.Number
, a.Name
, a.Debt
...
, case when c.IsPaid = 1 then c.[Date]
else null
end as Date_LastPayment
, case when c.IsPaid = 0 then c.[Date]
else null
end as Date_NextPayment
from ContractsTable a
inner join AgreementsTable b on b.ContractId = a.Id
inner join PaymentsTable c on c.AgreementId = b.Id
where b.IsValid = 1
) aa
group by aa.Id
, aa.Number
, aa.Name
, aa.Debt
...
I used 'min' for the Next Payment Date assuming there's multiple next payment dates.
SQL Fiddle

Max(PaymentsTable.Date) is not what you are looking for.
Please better define date of last payment and the date of next payment
select ContractsTable.Id, ContractsTable.Number, ContractsTable.Debt
, count(AgreementsTable.ID) as 'NumAgreements'
, max(PaymentsTable.Date)
from ContractsTable
left outter join AgreementsTable
on ContractsTable.ID = AgreementsTable.ID
left outter join PaymentsTable
on ContractsTable.ID = PaymentsTable.ID
group by ContractsTable.Id, ContractsTable.Number, ContractsTable.Debt

Related

Query is summing values multiple times

Hi my query below is summing multiple values based on #cropseasons in my table. Since i have 4 crop seasons it seems to be multiplying the values by 4 since i have crop season as 1, 2, 3 or 4. All i want is values for 1 crop season. Can anyone assist? I have crop season in both tables.
With Summary as (
Select B_NAME as Branch, LOC as Location
,SUM(payment) as Gallons
,SUM(case when printed = 1 THEN Fee ELSE NULL END) as FeeCollected
,SUM(case when printed = 0 THEN Fee ELSE NULL END) as FeeNotCollected
,SUM(case when printed = 1 THEN Payment ELSE NULL END) as GallonsIssued
,SUM(case when printed = 0 THEN Payment ELSE NULL END) as GallonsNotIssued
From SicbWeeklyDeliveriesFuelArchive F Inner Join FarmerGroups G ON G.BSI_CODE = F.BSI_CODE
Where F.CROP_SEASON = #cropseason
Group By B_NAME, LOC
)
SELECT Branch
,Location
,Gallons
,GallonsIssued
,GallonsNotIssued
,FeeCollected
,FeeNotCollected
,((GallonsIssued/Gallons) * 100) as pct_GallonsCollected
FROM Summary
Order by Location, Branch
SicbWeeklyDeliveriesFuelArchive
+-------+----------+-------------+-----+---------+------+-------------+---------+
| ID | BSI_CODE | B_NAME | LOC | PAYMENT | FEE | CROP_SEASON | PRINTED |
+-------+----------+-------------+-----+---------+------+-------------+---------+
| 18735 | 2176 | SAN NARCISO | CZ | 85 | 8.5 | 4 | 0 |
| 18738 | 2176 | SAN NARCISO | CZ | 65 | 6.5 | 4 | 0 |
| 18739 | 10494 | SAN NARCISO | CZ | 85 | 8.5 | 3 | 0 |
+-------+----------+-------------+-----+---------+------+-------------+---------+
FarmerGroups
+-------+----------+-------------+-------------+
| ID | BSI_CODE | CROP_SEASON | BRANCH |
+-------+----------+-------------+-------------+
| 10473 | 2176 | 4 | SAN NARCISO |
| 11478 | 2176 | 3 | SAN NARCISO |
| 12787 | 10494 | 4 | SAN ROMAN |
+-------+----------+-------------+-------------+
It seems your join criteria is incomplete. The tables share BSI_CODE and CROP_SEASON, so I guess you want:
FROM sicbweeklydeliveriesfuelarchive f
JOIN farmergroups g ON g.bsi_code = f.bsi_code AND g.crop_season = f.crop_season
WHERE f.crop_season = #cropseason
But that's just guessing. Only you know how the tables are really related, what their rows represent, what columns make a row unique and what result you are actually after. Why do you join farmergroups at all? It looks like you are not really using the table in your query.

Select from a concatenation of two columns after a left join

Problem description
Let the tables C and V have those values
>> Table V <<
| UnID | BillID | ProductDesc | Value | ... |
| 1 | 1 | 'Orange Juice' | 3.05 | ... |
| 1 | 1 | 'Apple Juice' | 3.05 | ... |
| 1 | 2 | 'Pizza' | 12.05 | ... |
| 1 | 2 | 'Chocolates' | 9.98 | ... |
| 1 | 2 | 'Honey' | 15.98 | ... |
| 1 | 3 | 'Bread' | 3.98 | ... |
| 2 | 1 | 'Yogurt' | 8.55 | ... |
| 2 | 1 | 'Ice Cream' | 7.05 | ... |
| 2 | 1 | 'Beer' | 9.98 | ... |
| 2 | 2 | 'League of Legends RP' | 40.00 | ... |
>> Table C <<
| UnID | BillID | ClientName | ... |
| 1 | 1 | 'Alexander' | ... |
| 1 | 2 | 'Tom' | ... |
| 1 | 3 | 'Julia' | ... |
| 2 | 1 | 'Tom' | ... |
| 2 | 2 | 'Alexander' | ... |
Table C have the values of each product, which is associated with a bill number. Table V has the relationship between the client name and the bill number. However, the bill number has a counter that is dependent on the UnId, which is the store unity ID. That being said, each store has it`s own Bill number 1, number 2, etc. Also, the number of bills from each store are not equal.
Solution description
I'm trying to make select between the C left join V without sucess. Because each BillID is dependent on the UnID, I have to make the join considering the concatenation between those two columns.
I've used this script, but it gives me an error.
SELECT
SUM(C.Value),
V.ClientName
FROM
C
LEFT JOIN
V
ON
CONCAT(C.UnID, C.BillID) = CONCAT(V.UnID, V.BillID)
GROUP BY
V.ClientName
and SQL server returns me this 'CONCAT' is not a recognized built-in function name.
I'm using Microsoft SQL Server 2008 R2
Is the use of CONCAT wrong? Or is it the way I tried to SELECT? Could you give me a hand?
[OBS: The tables I've present you are just for the purpose of explaining my difficulties. That being said, if you find any errors in the explanation, please let me know to correct them.]
You should be joining on the equality of the UnID and BillID columns in the two tables:
SELECT
c.ClientName,
COALESCE(SUM(v.Value), 0) AS total
FROM C c
LEFT JOIN V v
ON c.UnID = v.UnID AND
c.BillID = v.BillID
GROUP BY
c.ClientName;
In theory you could try joining on CONCAT(UnID, BillID). However, you could run into problems. For example, UnID = 1 with BillID = 23 would, concatenated together, be the same as UnID = 12 and BillID = 3.
Note: We wrap the sum with COALESCE, because should a given client have no entries in the V table, the sum would return NULL, which we then replace with zero.
concat is only available in sql server 2012.
Here's one option.
SELECT
SUM(C.Value),
V.ClientName
FROM
C
LEFT JOIN
V
ON
cast(C.UnID as varchar(100)) + cast(C.BillID as varchar(100)) = cast(V.UnID as varchar(100)) + cast(V.BillID as varchar(100))
GROUP BY
V.ClientName

SQL Server - Master / Detail - get extract exact detail item match

I need help to extract the exact item match from two table. I want from Detail Table all the order that exists in Temp Detail and Master and Temp Master itemQty are the same.
example: in this case I need the sum of master.Amount for all the order which ItemQty is 3 and the detail table has the exact same value of temp Detail.
Master
OrderId| Amount | ItemQty |Status
------------------------------------------
125 | 36.75 | 3 | A |
------------------------------------------
128 | 11.95 | 5 | A |
------------------------------------------
Detail contain lot of order detail
------------------------------------------
OrderId| ItemId | Qty | Price |
------------------------------------------
125 | 12345 | 1 | 11.00 |
------------------------------------------
125 | 23456 | 1 | 12.75 |
------------------------------------------
125 | 34567 | 1 | 13.00 |
------------------------------------------
Temp Master
------------------------------------------
|OrderId| Amount | ItemQty |Status
------------------------------------------
|9999 | 36.75 | 3 | A |
------------------------------------------
Temp Detail
------------------------------------------
|OrderId | ItemId | Qty | Price |
------------------------------------------
| 9999 | 12345 | 1 | 11.00 |
------------------------------------------
| 9999 | 23456 | 1 | 12.75 |
------------------------------------------
| 9999 | 34567 | 1 | 13.00 |
------------------------------------------
thank you in advance
You can try with something like this
select m.OrderId, sum(m.amount)
from master m
join detail d
on m.OrderId = d.OrderId
join tempDetail td
on m.OrderId = td.OrderId
where m.ItemQty = 3
group by m.OrderId
having sum(d.Qty * d.Price) = sum(td.Qty * td.Price)
My best guess:
select Masterr.OrderId,
sum(Masterr.Amount)
from Masterr
where Masterr.ItemQty = 3
and exists(select *
from Detail
join TempMaster on TempMaster.ItemQty = Masterr.ItemQty
join TempDetail on TempDetail.OrderId = TempMaster.OrderId
where Detail.OrderId = Masterr.OrderId
and TempDetail.ItemId = Detail.ItemId
and TempDetail.Qty = Detail.Qty
and TempDetail.Price = Detail.Price)
group by Masterr.OrderId;

Joining 3 tables on a date criteria

I need help with this.
Tbl: WarehouseInventory
Date | DelRec | ProductId | Quantity
2015-09-10 | 110 | 1 | 100
2015-09-12 | 111 | 1 | 100
2015-09-12 | 111 | 2 | 200
2015-09-12 | 111 | 3 | 300
Tbl: Withdrawals
Date | ID | ProductId | Quantity | CustomerId
2015-09-11 | 1 | 1 | 400 | 2
2015-09-12 | 1 | 1 | 100 | 1
2015-09-12 | 2 | 2 | 200 | 1
2015-09-12 | 3 | 3 | 300 | 1
Tbl: Customers
Customer Id | Name
1 | Somebody
2 | Someone
The output should be like this
DelRec | Date Added | ProductId | Stocked | Withdrawn | Customer
110 | 2015-09-10 | 1 | 100 | 0 | NULL
0 | 2015-09-11 | 1 | 0 | 400 | Someone
111 | 2015-09-12 | 1 | 100 | 100 | Somebody
111 | 2015-09-12 | 2 | 200 | 200 | Somebody
111 | 2015-09-12 | 3 | 300 | 300 | Somebody
This is what I have come up so far and it's giving me a wrong output
select wi.DateAdded as 'Date Added', max(wi.DeliveryReceipt) as 'Delivery Receipt', wi.ProductId as 'Product',
max(isnull(wi.Quantity, 0)) as 'Stocked', max(isnull(w.Quantity, 0)) as 'Withdrawn', e.Customers as 'Customer'
from WarehouseInventory wi
cross join Withdrawals w
cross join Customer e
group by wi.DateAdded, wi.ProductId, e.Customers, wi.DeliveryReceipt, w.ProductId
Basically, I need to join the two tables on the date and product and if there is a null value in one of the tables, just make it 0. I appreciate your help.
You can use a FULL OUTER JOIN:
SELECT DelRec,
COALESCE(wi.[Date], wd.[Date]) AS Date_Added,
COALESCE(wi.ProductId, wd.ProductId) AS ProductId,
COALESCE(wi.Quantity, 0) AS Stocked,
COALESCE(wd.Quantity, 0) AS Withdrawn,
c.Name AS Customer
FROM WarehouseInventory AS wi
FULL OUTER JOIN Withdrawals AS wd
ON wi.[Date] = wd.[Date] AND wi.ProductId = wd.ProductId
LEFT JOIN Customers AS c ON c.[Customer Id] = wd.CustomerId
ORDER BY Date_Added
You have a few inconsistencies between your example table and your query, but here's the basic gist:
You want to FULL OUTER JOIN your Warehouse delivery (A) and Withdrawal (B) tables on both product and date
Make sure you coalesce(A, B) for both date and product
Sum the quantities from each table, then coalesce outside each aggregate to get zeros (since one column can be all nulls).
Here:
select
coalesce(wi.DateAdded, w.date) as 'Date Added',
max(wi.DeliveryReceipt) as 'Delivery Receipt',
coalesce(wi.ProductId, w.productId) as 'Product',
coalesce(sum(wi.Quantity), 0) as 'Stocked',
coalesce(sum(w.Quantity), 0) as 'Withdrawn',
e.name as 'Customer'
from WarehouseInventory wi
full outer join Withdrawals w on w.date = wi.dateadded and w.productId = wi.productId
left join Customer e on e.customerId = w.customerId
group by
coalesce(wi.DateAdded, w.date),
coalesce(wi.ProductId, w.productId),
e.name

Dynamic columns in sql Join condition

Customer
customer_id | customer_name | customer_city | customer_number
---------------------------------------------------------------
1 | john | sanjose | 978234
2 | chris | newyork | 293
3 | mary | madrid | 342943
4 | tom | bangkok | 8627093
---------------------------------------------------------------
Data
data_id | data_name | data_city | data_number | data_cust_id | customer_id
--------------------------------------------------------------------------------------------
1 | abc | xyz | 990 | 1 | NULL
2 | john | sanjose | 978234 | 1 | NULL
3 | mary | madrid | 8627093 | 3 | NULL
4 | tom | LA | 7729 | 4 | NULL
ActionType
action_id | action_description
-----------------------------------
1 | customer_name
2 | customer_number
3 | customer_city
DataToAction
id | data_id | action_id
--------------------------
1 | 1 | 1
2 | 1 | 2
4 | 2 | 1
5 | 2 | 2
6 | 2 | 3
7 | 3 | 1
8 | 3 | 2
9 | 4 | 1
There are 4 tables -
Customer - Has customer datails
Data - Raw data pulled from an external source (has customer data and others)
ActionType - Has the column names which will be used in a join condition
DataToAction - For each of the raw data row in Data table, the columns to be used in the join is specified here.
Objective - To populate customer_id in 'Data' table.
I need something like this
UPDATE D
SET D.customer_id = C.customer_id
FROM Data D
INNER JOIN Customer C on D.data_cust_id = C.customer_id
WHERE *("GET THE COLUMNS TO BE MATCHED FROM DATATOACTION TABLE AND USE HERE")*
For eg., for Data id 1, i will update customer_id based on customer_name & customer_number, for data id 2 i will udpate customer_id based on customer_name, customer_number & customer_city and so on.
How do I apply the dynamic column conditions in the where clause for each of the row wherein the columns to be matched are specified in a different table.
Well the question is quite unclear. Can u elaborate the final resulset.
Purpose of ActionType table??
UPDATE D
SET D.customer_id = C.customer_id
FROM Data D
INNER JOIN Customer C on D.data_cust_id = C.customer_id
INNER JOIN DataToAction DA ON DA.data_id = D.data_id