How to make a query that return data of rows related to each row in table - sql

i have some tables about Double-entry bookkeeping.
table VoucherDetail Contains Accounting Entries for Each Voucher and
other tables are Accounts Group/Ledger/Definitive
here are diagrams of tables
im trying to get opposite side of an entry and show it in a custom column that matches entry debit/credit amount(Ref to image 2).
i did some google search and find nothing. here is the query i made so far(Ref to image 1):
SELECT
dbo.Vouchers.VoucherId,
vd.VoucherDetailIndex AS ind,
vd.Debit,
vd.Credit,
vd.Description,
CONCAT ( ag.Name, '_', al.Name, '_', ad.Name ) AS names,
CONCAT ( ag.GroupId, '_', al.LedgerId, '_', ad.DefinitiveId ) AS ids
FROM dbo.Vouchers
JOIN dbo.VoucherDetails AS vd ON vd.Voucher_VoucherIndex = dbo.Vouchers.VoucherIndex
JOIN dbo.AccDefinitives AS ad ON vd.AccDefinitive_DefinitiveIndex = ad.DefinitiveIndex
JOIN dbo.AccLedgers AS al ON ad.AccLedger_LedgerIndex = al.LedgerIndex
JOIN dbo.AccGroups AS ag ON al.AccGroup_GroupIndex = ag.GroupIndex
here is the result im getting :
result i want to be :
here is an example to explain what i need :
EVENT :
we put 10$ on bank as our Equity, now we need to create a voucher for this:
INSERT INTO Vouchers(VoucherIndex, VoucherId, VoucherDate, Description) VALUES
(1, 1, 2019/01/01, initial investment);
and now we need to add Entry of this event to VoucherDetail of Voucher 1
which will have 2 entry; 1 for cash and 1 for Equity :
INSERT INTO VoucherDetails(VoucherDetailIndex, Debit, Credit, Description AccDefinitive_DefinitiveIndex, AccLedger_LedgerIndex, Voucher_VoucherIndex, EntityOrder) VALUES
(1, 10$, 0, 'Put Cash on Bank as initial Investment', 10101, 101, 1, 1),
(2, 0, 10$, 'initial Investment', 50101, 501, 1, 2);
now we run the first query i provided here is the result
now we have our common result, lets get to the problem
imagine someone filled these tables with 10000 row data
and we need to find Voucher no.10, with 20 entries inside VoucherDetail
we get these entries by doing a simple query.
but we don't know which related to which(like in above example Cash with 10$ debt related to Equity with 10$ credit)
if we want to know it, we need to spend time on it every time we need to find something
the query need to search whole table and find opposite side related to each row based on Debit or Credit value of row
this should be the result i wrote in excel :
as you can see in the image above there is 2 new columns added
Account in opposite Side and Account ID in opposite side
first row refers to Equity which related to Cash and
second row refers to Cash Which related to Equity.

As far as I can see, what you need to be able to do is join two VoucherDetail records that have the same Voucher_VoucherIndex value (let's call this VoucherID for brevity). However, the only two things these records have in common is their VoucherID and the fact that the Debit value = the Credit value in the other, and vice versa.
In the comments you mentioned that multiple VoucherDetail rows with the same VoucherID can have the same Debit value (and I presume Credit value). If this wasn't the case, you could add something like this to your query:
JOIN dbo.VoucherDetails AS vd_opposite
ON vd.Voucher_VoucherIndex = vd_opposite.Voucher_VoucherIndex
AND (vd.Debit = vd_opposite.Credit OR vd.Credit = vd_opposite.Debit)
You can't do this though, because Debit/Credit and VoucherID together are not enough to be unique, so you might pick up extra rows in the join that you don't want.
Therefore, your only option is to add a new ID field to your table (maybe called SaleID or something) that definitively links the two rows that represent opposite sides of the same "sale" with a common ID. Then, the above JOIN would look like this:
JOIN dbo.VoucherDetails AS vd_opposite
ON vd.Voucher_VoucherIndex = vd_opposite.Voucher_VoucherIndex
AND vd.SaleID = vd_opposite.SaleID
In addition to adding that JOIN, you would need to join the new vd_opposite table against all of the dbo.Acc* tables again to get access to the data you want, and obviously add the fields from those tables that you want in the results to your SELECT fields.

Related

How do I do a sum per id?

SELECT distinct
A.PROPOLN, C.LIFCLNTNO, A.PROSASORG, sum (A.PROSASORG) as sum
FROM [FPRODUCTPF] A
join [FNBREQCPF] B on (B.IQCPLN=A.PROPOLN)
join [FLIFERATPF] C on (C.LIFPOLN=A.PROPOLN and C.LIFPRDCNT=A.PROPRDCNT and C.LIFBNFCNT=A.PROBNFCNT)
where C.LIFCLNTNO='2012042830507' and A.PROSASORG>0 and A.PROPRDSTS='10' and
A.PRORECSTS='1' and A.PROBNFLVL='M' and B.IQCODE='B10000' and B.IQAPDAT>20180101
group by C.LIFCLNTNO, A.PROPOLN, A.PROSASORG
This does not sum correctly, it returns two lines instead of one:
PROPOLN LIFCLNTNO PROSASORG sum
1 209814572 2012042830507 3881236 147486968
2 209814572 2012042830507 15461074 463832220
You are seeing two rows because A.PROSASORG has two different values for the "C.LIFCLNTNO, A.PROPOLN" grouping.
i.e.
C.LIFCLNTNO, A.PROPOLN, A.PROSASORG together give you two unique rows.
If you want a single row for C.LIFCLNTNO, A.PROPOLN, then you may want to use an aggregate on A.PROSASORG as well.
Your entire query is being filtered on your "C" table by the one LifClntNo,
so you can leave that out of your group by and just have it as a MAX() value
in your select since it will always be the same value.
As for you summing the PROSASORG column via comment from other answer, just sum it. Hour column names are not evidently clear for purpose, so I dont know if its just a number, a quantity, or whatever. You might want to just pull that column out of your query completely if you want based on a single product id.
For performance, I would suggest the following indexes on
Table Index
FPRODUCTPF ( PROPRDSTS, PRORECSTS, PROBNFLVL, PROPOLN )
FNBREQCPF ( IQCODE, IQCPLN, IQAPDAT )
FLIFERATPF ( LIFPOLN, LIFPRDCNT, LIFBNFCNT, LIFCLNTNO )
I have rewritten your query to put the corresponding JOIN components to the same as the table they are based on vs all in the where clause.
SELECT
P.PROPOLN,
max( L.LIFCLNTNO ) LIFCLNTNO,
sum (P.PROSASORG) as sum
FROM
[FPRODUCTPF] P
join [FNBREQCPF] N
on N.IQCODE = 'B10000'
and P.PROPOLN = N.IQCPLN
and N.IQAPDAT > 20180101
join [FLIFERATPF] L
on L.LIFCLNTNO='2012042830507'
and P.PROPOLN = L.LIFPOLN
and P.PROPRDCNT = L.LIFPRDCNT
and P.PROBNFCNT = L.LIFBNFCNT
where
P.PROPRDSTS = '10'
and P.PRORECSTS = '1'
and P.PROBNFLVL = 'M'
and P.PROSASORG > 0
group by
P.PROPOLN
Now, one additional issue you will PROBABLY be running into. You are doing a query with multiple joins, and it appears that there will be multiple records in EACH of your FNBREQCPF and FLIFERATPF tables for the same FPRODUCTPF entry. If you, you will be getting a Cartesian result as the PROSASORG value will be counted for each instance combination in the two other tables.
Ex: FProductPF has ID = X with a Prosasorg value of 3
FNBreQCPF has matching records of Y1 and Y2
FLIFERATPF has matching records of Z1, Z2 and Z3.
So now your total will be equal to 3 times 6 = 18.
If you look at the combinations, Y1:Z1, Y1:Z2, Y1:Z3 AND Y2:Z1, Y2:Z2, Y2:Z3 giving your 6 entries that qualify, times the original value of 3, thus bloating your numbers -- IF such multiple records may exist in each respective table. Now, imagine if your tables have 30 and 40 matching instances respectively, you have just bloated your totals by 1200 times.

SQL Subtract Values From Table 1 When The Row Exists In Table 2

I have two tables, tblTasks and tblOffsets. The tblTasks has all of these Tasks that are being funded and tblOffsets has references to lines in tblTasks that are being funded by outside money.
Both have the same columns except tblOffsets has an extra column called "Source" to keep track of where the money is coming form.
Columns
Appropriation, PerformerGroup, Performer, Contract, ID, IDExt, Labor, Material, Travel, FiscalYear
The primary key is actually a collection of columns from this table: Appropriation, PerformerGroup, Performer, Contract, FiscalYear, ID, and IDExt. Each row has a unique combination of these columns.
Now what I want to do is get a subquery (or maybe I need to make a new table?) that takes tblTasks and subtracts the values from tblOffsets for the lines that exist in tblOffsets.
I've tried to write this code that obviously doesn't work but it should give you an idea of what I'm talking about:
SELECT
tb.Appropriation,
tb.PerformerGroupID,
tb.PerformerID,
tb.Contract,
tb.ID,
tb.IDExt,
(tb.Labor - o.Labor) AS Labor,
(tb.Material - o.Material) AS Material,
(tb.Travel - o.Travel) AS Travel
FROM tblTaskBooks tb, tblOffsets o
WHERE tblTaskBooks.Appropriation = tblOffsets.Appropriation
AND tblTaskBooks.PerformerGroupID= tblOffsets.PerformerGroupID
AND tblTaskBooks.PerformerID = tblOffsets.PerformerID
AND tblTaskBooks.Contract = tblOffsets.Contract
AND tblTaskBooks.ID = tblOffsets.ID
AND tblTaskBooks.IDExt = tblOffsets.IDExt
AND tblTaskBooks.FiscalYear = tblOffsets.FiscalYear
When I do this however, Access keeps asking for an input for Appropriation and etc. Is the problem that the two tables have different number of rows?

Can't get A sum to join to a table

I have two tables, one contains a set of line items with amounts:
LEDGERTRANS:
Invoice ID LineAmount
CM-00011054 -122.500000000000
CM-00011054 -246.000000000000
CM-00011054 -159.840000000000
CM-00011054 -39.3600000000000
And one with an item number i want, which happens to have a field, AMOUNTMST that is the sum of the above amounts
CUSTINVOICETRANS
INVOICE ID AMOUNTMST
110100 -567.700000000000
400100 567.700000000000
I would like to take the sum of the CustInvoiceTrans lines, then grab the corresponding invoice id from the LedgerTrans Table.
This is for SQL Server 2008R2.
As I said, all I want is the InvoiceId. I think i'm making this too complicated. any help appreciated

Create one query with sum and count with each value pulled from a different table

I am trying to create a query that pulls two different aggregated values from three different tables during a specific date range. I am working in Access 2003.
I have:
tblPO which has the high level purchase order description (company name, shop order #, date of order, etc)
tblPODescription which has the dollar values of the individual line items from customers the purchase order
tblCostSheets which as a breakdown of the individual pieces that we need to manufacture to satisfy the customers purchase order.
I am looking to create a query that will allow me, based on the Shop Order #, to get both the sum of the dollar values from tblPODescriptions and the count of the different type of pieces we need to make from tblCostSheets.
A quick caveat: the purchase order may have 5 line items for a sum of say $1560 but it might take us making 8 or 9 different parts to satisfy those 5 line items. I can easily create a query that pulls either the sum or the count by themselves, but when I created my query with both, I end up with numbers that are multipled versions of what I want. I believe it is multiplying my piece counts and dollar values.
SELECT DISTINCTROW tblPO.CompanyName, tblPO.ShopOrderNo, tbl.OrderDate, Sum(tblPODescriptions.ItemAmount) AS SumOfItemAmount, Count(tblCostSheets.Description) AS CountOfDescription
FROM (tblPO INNER JOIN tblPODescriptions ON (tblPO.CompanyName = tblPODescriptions.CompanyName) AND (tblPO.PurchaseOrderNo = tblPODescriptions.PurchaseOrderNo) AND (tblPO.PODate = tblPODescriptions.PODate)) INNER JOIN tblCostSheets ON tblPO.ShopOrderNo = tblCostSheets.ShopOrderNo
GROUP BY tblPO.CompanyName, tblPO.ShopOrderNo, tblPO.OrderDate
HAVING (((tblPO.OrderDate) Between [Enter Start Date:] And [Enter End Date:]));

looping through a numeric range for secondary record ID

So, I figure I could probably come up with some wacky solution, but i figure i might as well ask up front.
each user can have many orders.
each desk can have many orders.
each order has maximum 3 items in it.
trying to set things up so a user can create an order and the order auto generates a reference number and each item has a reference letter. reference number is 0-99 and loops back around to 0 once it hits 99, so orders throughout the day are easy to reference for the desks.
So, user places an order for desk #2 of 3 items:
78A: red stapler
78B: pencils
78C: a kangaroo foot
not sure if this would be done in the program logic or done at the SQL level somehow.
was thinking something like neworder = order.last + 1 and somehow tying that into a range on order create. pretty fuzzy on specifics.
Without knowing the answer to my comment above, I will assume you want to have the full audit stored, rather than wiping historic records; as such the 78A 78B 78C type orders are just a display format.
If you have a single Order table (containing your OrderId, UserId, DeskId, times and any other top-level stuff) and an OrderItem table (containing your OrderItemId, OrderId, LineItemId -- showing 1,2 or 3 for your first and optional second and third line items in the order, and ProductId) and a Product table (ProductId, Name, Description)
then this is quite simple (thankfully) using the modulo operator, which gives the remainder of a division, allowing you in this case to count in groups of 3 and 100 (or any other number you wish).
Just do something like the following:
(you will want to join the items into a single column, I have just kept them distinct so that you can see how they work)
Obviously join/query/filter on user, desk and product tables as appropriate
select
o.OrderId,
o.UserId,
o.DeskId
o.OrderId%100 + 1 as OrderNumber,
case when LineItem%3 = 1 then 'A'
when LineItem%3 = 2 then 'B'
when LineItem%3 = 0 then 'C'
end as ItemLetter,
oi.ProductId
from tb_Order o inner join tb_OrderItem oi on o.OrderId=oi.OrderId
Alternatively, you can add the itemLetter (A,B,C) and/or the OrderNumber (1-100) as computed (and persisted) columns on the tables themselves, so that they are calculated once when inserted, rather than recalculating/formatting when they are selected.
This sort-of breaks some best practice that you store the raw data in the DB and you format on retrieval; but if you are not going to update the data and you are going to select the data for more than you are going to write the data; then I would break this rule and calculate your formatting at insert time