How to sum Accounts by account code length? - sql

I have 2 tables: DimAccounts and FactBudget.
DimAccounts example:
AccountKey AccountCode AccountName AccountGroup AccountType
1.6 1 6 1 NN 6 S
1.6 10 6 10 MMM 6 S
1.6 101 6 101 TTT 6 S
1.6 1010 6 1010 IIII 6 B
1.6 1011 6 1011 OOOO 6 B
1.6 1012 6 1012 KKK 6 B
FactBudget example:
TimeKey AccountKey Debit Credit
20110719 1.6 1010 20.00 5.00
20110719 1.6 1011 15.00 0.00
20110719 1.6 1000 5.00 0.00
20110719 1.6 1012 10.00 5.00
20110719 1.6 1112 10.00 0.00
In FactBudget are many Accounts just with type B. I need to get Debit and Credit Sums for Account type S (Sum).
Solution example for example data:
TimeKey AccountKey Debit Credit
20110719 1.6 1 60.00 10.00
20110719 1.6 10 50.00 10.00
20110719 1.6 101 45.00 10.00
To calculate debit and credit for sum account 1.6 101 (7 symbols with whitespace) we need to substring all acounts in factbudget up to 7 symbols (1.6 1012 -> 1.6 101, 1.6 1112 -> 1.6 111, 1.6 1011->1.6 101) and then where are they equal
(1.6 101 = 1.6 101) to group by timekey and sum debit and credit.
To calculate debit and credit for sum account 1.6 1 (5 symbols with whitespace) we need to substring all acounts in factbudget up to 5 symbols (1.6 1012 -> 1.6 1, 1.6 1112 -> 1.6 1, 1.6 1011->1.6 1) and then where are they equal
(1.6 1 = 1.6 1) to group by timekey and sum debit and credit:) and so on.
So, How to get S Accounts Debit and Cred Sum by TimeKey and AccountKey?

Basically, you could take this answer and just change one of the join conditions:
SELECT
f.TimeKey,
s.AccountKey,
SUM(f.Debit) AS Debit,
SUM(f.Credit) AS Credit
FROM DimAccounts s
INNER JOIN DimAccounts b ON b.AccountCode LIKE s.AccountCode + '%'
/* alternatively: ON s.AccountCode = LEFT(b.AccountCode, LEN(s.AccountCode)) */
INNER JOIN FactBudget f ON f.AccountKey = b.AccountKey
WHERE s.AccountType = 'S'
AND b.AccountType = 'B'
GROUP BY
f.TimeKey,
s.AccountKey

SELECT F.TimeKey,
D.AccountKey,
SUM(F.Debit) Debit,
SUM(F.Credit) Credit
FROM DimAccounts D
INNER JOIN FactBudget F ON F.AccountKey LIKE D.AccountKey + '%'
WHERE D.AccountType = 'S'
GROUP BY F.TimeKey,
D.AccountKey

Maybe something like this:
SELECT
FactBudget.TimeKey,
DimAccounts.AccountKey,
SUM(FactBudget.Debit) AS Debit,
SUM(FactBudget.Credit) AS Credit
FROM
DimAccounts
JOIN FactBudget
ON DimAccounts.AccountKey=
SUBSTRING(FactBudget.AccountKey,0,DATALENGTH(DimAccounts.AccountKey)+1)
WHERE
DimAccounts.AccountType='S'
GROUP BY
FactBudget.TimeKey,
DimAccounts.AccountKey

Related

PostgreSQL query not fetching correct result for the conditional comparison of aggregate function

I have a products table with following values with id as INT and profit as numeric data type
id profit
1 6.00
2 3.00
3 2.00
4 3.00
5 2.00
6 8.00
7 4.00
8 3.00
9 1.00
10 4.00
11 10.00
12 3.00
13 6.00
14 5.00
15 2.00
16 7.00
17 6.00
18 5.00
19 2.00
20 16.00
21 3.00
22 6.00
23 5.00
24 5.00
25 1.00
26 4.00
27 1.00
28 7.00
29 11.00
30 2.00
31 1.00
32 3.00
33 2.00
34 5.00
35 4.00
I want to fetch id's which have profit more than average profit
My QUERY:
SELECT product_id,profit
FROM products
GROUP BY product_id,profit
HAVING profit > AVG(profit)::INT
But, the above query return's empty result.
when you execute the group by query, the records are grouped based on the parameters and then where/having clauses are applied.
so first group is student id 1 and further grouped by profit 6.00 making its average as 6.00 and with having condition profit >avg(profit), there are no records which match the criteria.
same for all other records. that is why you get empty result set as no number can be > itself.
based on your description though, it can be achieved by multiple selects.
select * from products where profit >(select avg(profit) from products)

query to get the SUM

Supposed I have a data of
code_table
code_id | code_no | stats |
2 60 22A3
3 60 22A3
value_table
value_no | amount_value_one | amount_value_two | amount_diff | code_no | sample_no | code_id
1 1200.00 400.00 800.00 60 90 2
1 600.00 200.00 400.00 60 100 3
1 1800.00 600.00 1200.00 60 110 2
2 1200.00 1200.00 0.00 60 110 2
2 800.00 600.00 200.00 60 90 2
2 400.00 0.00 400.00 60 100 3
What I want to happen is to get all the SUM of amount_value_two and just retain the first amount_value_one which has the value_no = 1
the output can be conclude as
amount_value_one | SUM_of_amount_value_two | amount_diff | sample_no
1200.00 1000.00 200.00 90
600.00 200.00 400.00 100
1800.00 1.800.00 0.00 110
so far i have this following query
SELECT SUM(p.amount_value_one) as value_one,
SUM(p.amount_value_two) as value_two,
SUM(p.amount_diff) as amount_diff,
p.sample_no as sampleNo FROM value_table p
INNER JOIN code_table On code_table.code_no = p.code_no
WHERE code_table.code_id = p.code_id
AND code_table.stats = '22A3'
GROUP BY p.sample_no
the query above that I used is wrong because it gets the sum of both p.amount_value_one
and p.amount_diff
its just a test query because i cant imagine what would the query will look like.
Assuming that you have a column that specifies the ordering, then you can use that to figure out the "first" row. Then use conditional aggregation:
SELECT SUM(CASE WHEN seqnum = 1 THEN p.amount_value_one END) as value_one,
SUM(p.amount_value_two) as value_two,
SUM(p.amount_diff) as amount_diff,
p.sample_no as sampleNo
FROM (SELECT p.*,
ROW_NUMBER() OVER (PARTITION BY p.sample_no ORDER BY <ordering column>) as seqnum
FROM value_table p
) p JOIN
code_table ct
ON ct.code_no = p.code_no AND
ct.code_id = p.code_id
WHERE ct.stats = '22A3'
GROUP BY p.sample_no

How to select top 4 records of amount from 2 tables [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I have 2 tables one contain document detail as below :
Table1 : contains customer and total document amount.
DocEntry CustID CustName City DocAmount
1 GF002 Raffy N London 120.00
2 GF025 Jhon Liverpool 50.00
3 GF120 Keng London 125.25
4 GF055 Tung L. London 30.00
5 GF020 Lee H. Manchester 60.00
Table2 : contains item and item price of each document.
DocEntry LineNum ItemID ItemName ItemPrice Qty LineAmount
1 0 I0001 Mouse 6.00 5 30.00
1 1 I0002 Key Broad 6.00 5 30.00
1 2 I0200 Monitor 60.00 1 60.00
2 0 I0501 Ext.HDD1 50.00 1 50.00
3 0 I0665 Printer 125.00 1 125.00
4 0 I0002 Key Broad 6.00 4 24.00
4 1 I0001 Mouse 6.00 1 6.00
5 0 I0050 ODD 12.00 1 12.00
5 1 I0001 Mouse 6.00 8 48.00
I would like to select the top 3 of documents from Table1 which have highest DocAmount and in the top 3 selected have to show line detail from Table2
the result should be :
Row DocEntry CustID CustName DocAmount ItemID ItemName ItemPrice Qty LineAmount
1 3 GF120 Keng 125.25 I0665 Printer 125.00 1 125.00
2 1 GF002 Raffy N 120.00 I0001 Mouse 6.00 5 30.00
3 1 GF002 Raffy N 120.00 I0002 Key Broad 6.00 5 30.00
4 1 GF002 Raffy N 120.00 I0200 Monitor 60.00 1 60.00
5 5 GF020 Lee H. 60.00 I0050 ODD 12.00 1 12.00
5 5 GF020 Lee H. 60.00 I0001 Mouse 6.00 8 48.00
select Table2.DocEntry, CustID, CustName, DocAmount, ItemID, ItemName,
ItemPrice, Qty, LineAmount
from (select top 3 * from Table1 order by DocAmount desc) TopDocs
join Table2 on TopDocs.DocEntry=Table2.DocEntry
order by DocAmount desc
SQL Fiddle here.

Incremental count in SQL Server 2005

I am working with a Raiser's Edge database using SQL Server 2005. I have written SQL that will produce a temporary table containing details of direct debit instalments. Below is a small table containing the key variables for the question I'm going to ask, with some fictional data:
Donor_ID Instalment_ID Instalment_Date Amount
1234 1111 01/01/2011 £5.00
1234 1112 01/02/2011 £0.00
1234 1113 01/03/2011 £5.00
1234 1114 01/04/2011 £5.00
1234 1115 01/05/2011 £0.00
1234 1116 01/06/2011 £0.00
2345 2111 01/01/2011 £0.00
2345 2112 01/02/2011 £5.00
2345 2113 01/03/2011 £5.00
2345 2114 01/04/2011 £0.00
2345 2115 01/05/2011 £0.00
2345 2116 01/06/2011 £0.00
As you will see, some of the values in the Amount column are £0.00. This can occur when a donor has insufficient funds in their account, for example.
What I'd like to do is write a SQL query that will create a field containing an incremental count of consecutive £0.00 payments that resets after a non-£0.00 payment or after a change in Donor_ID. I have reproduced the above data below, with the field I'd like to see.
Donor_ID Instalment_ID Instalment_Date Amount New_Field
1234 1111 01/01/2011 £5.00
1234 1112 01/02/2011 £0.00 1
1234 1113 01/03/2011 £5.00
1234 1114 01/04/2011 £5.00
1234 1115 01/05/2011 £0.00 1
1234 1116 01/06/2011 £0.00 2
2345 2111 01/01/2011 £0.00 1
2345 2112 01/02/2011 £5.00
2345 2113 01/03/2011 £5.00
2345 2114 01/04/2011 £0.00 1
2345 2115 01/05/2011 £0.00 2
2345 2116 01/06/2011 £0.00 3
To help clarify what I'm looking for, I think what I'm looking to do would be similar to a winning streak field on a list of a football team's results. For example:
Opponent Score Winning_Streak
Arsenal 1-0 1
Liverpool 0-0
Swansea 3-1 1
Chelsea 2-1 2
Fulham 4-0 3
Stoke 0-0
Man Utd 1-3
Reading 2-1 1
I've considered various options, but have made no progress. Unless I've missed something obvious, I think that a solution more advanced than my current SQL programming level might be required.
If I am thinking about this problem correctly, I believe that you want a row number when the Amount is 0.00 pounds.
Select 0 as As InsufficientCount
, Donor_ID
, Installment_ID
, Amount
From [Table]
Where Amount > 0.00
Union
Select Row_Number() Over (Partition By Donor_ID Order By Installment_ID)
, Donor_ID
, Installment_ID
, Amount
From [Table]
Where Amount = 0.00
This union select should only give you 'ranks' where the Amount equals 0.
Am calling your new field streakAmount
ALTER TABLE instalments ADD streakAmount int NULL;
Then, to update the value:
UPDATE instalments
SET streakAmount =
(SELECT
COUNT(*)
FROM
instalments streak
WHERE
streak.donor_id = instalments.donor_id
AND
streak.instalment_date <= instalments.instalment_date
AND
(streak.instalment_date >
-- find previous instalment date, if any exists
COALESCE(
(
SELECT
MAX(instalment_date)
FROM
instalments prev
WHERE
prev.donor_id = instalments.donor_id
AND
prev.amount > 0
AND
prev.instalment_date < instalments.instalment_date
)
-- otherwise min date
, cast('1753-1-1' AS date))
)
)
WHERE
amount = 0;
http://sqlfiddle.com/#!6/a571f/18

SQL Query to join two columns of a table with other tables

I have 3 tables as shown in the diagram:
The test data in each of these tables is as given below:
ACCOUNT_GROUP
GroupID Name
101 Bank Accounts
105 Cash-in-hand
113 Indirect Expenses
120 Purchase Accounts
122 Sales Accounts
125 Sundry Creditors
ACCOUNT_MASTER
AccID Name GroupID
1001 RBS A/C 23456 101
1002 HSBC A/C 123456 101
1003 CASH A/C 105
1004 DISCOUNT 113
1005 CASH SALES 122
1006 CASH PURCHASE 120
1007 JOHNSON 125
ACCOUNT_TXNS
TxnID TxnDate FromAccID ToAccID Amt CrDr
1 20-Jul-2011 1002 1003 250000 C
2 20-Jul-2011 1001 1002 985241 C
3 20-Jul-2011 1005 1003 65451 C
4 20-Jul-2011 1006 1003 412874 D
5 20-Jul-2011 1007 1003 521400 C
6 20-Jul-2011 1003 1007 200 D
I want to get the account names of both FromAccID and ToAccID and their group names in a single query like this:
TxnID TxnDate FromAcc FromAccGroup ToAcc ToAccountGroup Amt CrDr
1 20-Jul-2011 HSBC A/C 123456 Bank Accounts CASH A/C Cash-in-hand 250000 C
2 20-Jul-2011 RBS A/C 23456 Bank Accounts HSBC A/C 123456 Bank Accounts 985241 C
3 20-Jul-2011 CASH SALES Sales Accounts CASH A/C Cash-in-hand 65451 C
4 20-Jul-2011 CASH PURCHASE Purchase Accounts CASH A/C Cash-in-hand 412874 D
5 20-Jul-2011 JOHNSON Sundry Creditors CASH A/C Cash-in-hand 521400 C
6 20-Jul-2011 CASH A/C Cash-in-hand JOHNSON Sundry Creditors 200 D
Kindly help me to achieve this.
You can use the same table more than once in a single query, just use aliases.
Something like
SELECT *
FROM ACCOUNT_TXNS txns INNER JOIN
ACCOUNT_MASTER fromAcc ON txns.FromAccID = fromAcc.AccID INNER JOIN
ACCOUNT_GROUP fromAccGrp ON fromAcc.GroupID = fromAccGrp.GroupID INNER JOIN
ACCOUNT_MASTER toAcc ON txns.ToAccID = toAcc.AccID INNER JOIN
ACCOUNT_GROUP toAccGrp ON toAcc.GroupID = toAccGrp.GroupID