I have my table data as follows
TaxTypeCode1 TaxTypeCode2 PNO Amount
-----------------------------------------
TX01 TX02 124 600
TX02 null 124 700
TX03 TX04 124 200
TX04 null 124 300
TX05 TX06 126 400
TX06 null 127 500
TX07 null 128 800
I would like to write SQL query to retrieve data.
Conditions apply IF pno is same and TaxTypeCode1 contain TaxTypeCode2 then sum the amt, otherwise display actual amt
My expected output is
PNO Amount
---------------
124 1300
124 500
126 400
127 500
128 800
124 has 1300 because pno is same and TaxTypeCode2 (TX02) TaxTypeCode1 (TX02) are same then sum
TX01 (TX02) 124 600
(TX02) null 124 700
126 has 400 because pno is different and TaxTypeCode2 (TX02) TaxTypeCode1 (TX02) are same don't sum
TX05 (TX06) (126) 400
(TX06) null (127) 500
Can anyone tell how to write query to retrieve that data?
SELECT PNO,SUM(Amount)
FROM YOURTABLE
GROUP BY PNO;
This is your table and data:
CREATE TABLE Test
(
TaxTypeCode1 CHAR(4),
TaxTypeCode2 CHAR(4),
PNO INT,
Amount INT
)
INSERT INTO Test VALUES('TX01', 'TX02', 124, 600)
INSERT INTO Test VALUES('TX02', null, 124, 700)
INSERT INTO Test VALUES('TX03', 'TX04', 124, 200)
INSERT INTO Test VALUES('TX04', null, 124, 300)
INSERT INTO Test VALUES('TX05', 'TX06', 126, 400)
INSERT INTO Test VALUES('TX06', null, 127,500)
INSERT INTO Test VALUES('TX07', null, 128, 800)
and this is query for you:
SELECT PNO, SUM(Amount)
FROM Test
GROUP BY PNO, COALESCE(TaxTypeCode2, TaxTypeCode1)
Result matches your expected output.
I found that you really do is aggregating data by PNO and by second or first column (if second is empty). COALESCE(TaxTypeCode2, TaxTypeCode1) will return first not empty.
You can also use ISNULL(TaxTypeCode2, TaxTypeCode1). COALESCE can have more than 2 params like COALESCE(TaxTypeCode3, TaxTypeCode2, TaxTypeCode1).
See that:
SELECT COALESCE(TaxTypeCode2, TaxTypeCode1) as sumBy, * FROM Test
Related
I was hoping to find the sum from two tables with columns ID and Amount, grouping by ID.
My first attempt was to UNION the two tables first and then conduct a sum and group by, but I was hoping to know of a better way.
Inputs:
Table 1
ID Amount
123 100
123 100
145 500
167 600
Table 2
ID Amount
123 100
123 100
145 500
199 600
Output
ID Amount
123 400
145 1000
167 600
199 600
You can do:
select id, sum(amount) as amount
from (
select id, amount from table_1
union all
select id, amount from table_2
) x
group by id
I need to insert into a table from a temporary table without duplicating the data from temp table. ie , for each customer need to insert a single row with SpecialCreditNoteAwarded
My temporary table:
CustID SalesMasterID SpecialCreditNoteAwarded
------------------------------------------------
100 13139 92115
100 13148 92115
100 13150 92115
101 13204 1175
101 13205 1175
102 13209 650
102 13210 650
102 13211 650
Result table
CustID SaleID SpecialCreditNoteAwarded
-----------------------------------------
100 0 92115
101 0 1175
102 0 650
You can use the GROUP BY function in a SELECT statement to remove duplicates
INSERT INTO Table_rslt (CustID, SaleID, SpecialCreditNoteAwarded)
SELECT
CustID
,0
,SpecialCreditNoteAwarded
FROM #temp
GROUP BY CustID,SpecialCreditNoteAwarded;
You didn't specify your DBMS, so this answer is for SQL SERVER.
I am migrating financial data from a very large table (100 million+ of rows) by summarizing the amount and insert them into summary table. I ran into problem when the summary amount (3 billions) is larger than what the field in the summary table can hold (can only hold up to 999 millions.) Changing the field size is not an option as it requires a change process.
The only option I have is to divide the amount (the one that breach the size limit) into smaller ones so it can be inserted into the table.
I came across this SQL - I need to divide a total value into multiple rows in another table which is similar except the number of rows I need to insert is dynamic.
For simplicity, this is how the source table might look like
account_table
acct_num | amt
-------------------------------
101 125.00
101 550.00
101 650.00
101 375.00
101 475.00
102 15.00
103 325.00
103 875.00
104 200.00
104 275.00
The summary records are as follows
select acct_num, sum(amt)
from account_table
group by acct_num
Account Summary
acct_num | amt
-------------------------------
101 2175.00
102 15.00
103 1200.00
104 475.00
Assuming the maximum value in the destination table is 1000.00, the expected output will be
summary_table
acct_num | amt
-------------------------------
101 1000.00
101 1000.00
101 175.00
102 15.00
103 1000.00
103 200.00
104 475.00
How do I create a query to get the expected result? Thanks in advance.
You need a numbers table. If you have a handful of values, you can define it manually. Otherwise, you might have one on hand or use a similar logic:
with n as (
select (rownum - 1) as n
from account_table
where rownum <= 10
),
a as (
select acct_num, sum(amt) as amt
from account_table
group by acct_num
)
select acct_num,
(case when (n.n + 1) * 1000 < amt then 1000
else amt - n.n * 1000
end) as amt
from a join
n
on n.n * 1000 < amt ;
A variation along these lines might give some ideas (using the 1,000 of your sample data):
WITH summary AS (
SELECT acct_num
,TRUNC(SUM(amt) / 1000) AS times
,MOD(SUM(amt), 1000) AS remainder
FROM account_table
GROUP BY acct_num
), x(acct_num, times, remainder) AS (
SELECT acct_num, times, remainder
FROM summary
UNION ALL
SELECT s.acct_num, x.times - 1, s.remainder
FROM summary s
,x
WHERE s.acct_num = x.acct_num
AND x.times > 0
)
SELECT acct_num
,CASE WHEN times = 0 THEN remainder ELSE 1000 END AS amt
FROM x
ORDER BY acct_num, amt DESC
The idea is to first build a summary table with div and modulo:
ACCT_NUM TIMES REMAINDER
101 2 175
102 0 15
103 1 200
104 0 475
Then perform a hierarchical query on the summary table based on the number of "times" (i.e. rows) you want, with an extra for the remainder.
ACCT_NUM AMT
101 1000
101 1000
101 175
102 15
103 1000
103 200
104 475
How do i use the group by clause in the PIVOT operator?
I tried with the following code but i get the null values and the results are not getting aggregated.
select EmpName, CHN,HYD FROM location
PIVOT (Sum(salary) for EmpLoc in ([CHN], [HYD]))
AS
pivottable
I want the final output to be like this.
CHN HYD
kunder 400 200
shetty 150 150
or
CHN HYD Total
kunder 400 200 600
shetty 150 150 300
Total 550 350 900
Just add the derived column Total=CHN+HYD and a sub-query to create the Total Row
The Seq (though not displayed) will put the Total row at the bottom
Declare #YourTable table (EmpLoc varchar(25),EmpName varchar(25),Salary int)
Insert Into #YourTable values
('HYD','kunder',200)
,('HYD','shetty',150)
,('CHN','shetty',150)
,('CHN','kunder',200)
,('CHN','kunder',200)
Select EmpName, CHN,HYD,Total=CHN+HYD
From (
Select Seq=0,EmpLoc,EmpName,Salary From #YourTable
Union All
Select Seq=1,EmpLoc,'Total',Salary From #YourTable
) A
pivot (sum(Salary) for EmpLoc in ([CHN], [HYD])) P
Returns
EmpName CHN HYD Total
kunder 400 200 600
shetty 150 150 300
Total 550 350 900
Declare #YourTable table (EmpLoc varchar(25),EmpName varchar(25),Salary int)
Insert Into #YourTable values
('HYD','kunder',200)
,('HYD','shetty',150)
,('CHN','shetty',150)
,('CHN','kunder',200)
,('CHN','kunder',200)
;with cte as
(
SELECT * from
(
select * from #YourTable
) as y
pivot
(
sum(salary)
for EmpLoc in ([CHN], [HYD])
) as p
)
SELECT
EmpName,sum(CHN)CHN ,sum(HYD)HYD
FROM CTE
GROUP BY EmpName;
I have no issue using your code from your example to get your desired results. I am guessing that your query is not as simple as your example, and as such is introducing other complications not shown here.
You may need to use a subquery and pivot using just the columns necessary for the pivot and join back to the rest of your query to get the results you are looking for using pivot().
Using conditional aggregation may be a simpler solution:
select
empname
, CHN = sum(case when emploc = 'CHN' then salary else 0 end)
, HYD = sum(case when emploc = 'HYD' then salary else 0 end)
--, Total = sum(salary) /* Optional total */
from location
group by empname
rextester demo: http://rextester.com/LYRH81756
returns:
+---------+-----+-----+
| EmpName | CHN | HYD |
+---------+-----+-----+
| kunder | 400 | 200 |
| shetty | 150 | 150 |
+---------+-----+-----+
The heading of this question is probably poorly worded as I am finding it difficult to explain concisely what I want, other than to provide some demo data.
I have a query which returns the following data from a sql table:
ID Job User Amount
1 101 Bob 100
2 101 Pete 500
3 102 Bob 400
4 102 Pete 200
5 101 Pete 850
6 102 Bob 650
What I want is the query to also return an additional field called (Difference), which contains the difference between the Amount in consecutive entries for the same User and Job. Hence the data I would like returned would be as follows:
ID Job User Amount Diff
1 101 Bob 100 100
2 101 Pete 500 500
3 102 Bob 400 400
4 102 Pete 200 200
5 101 Pete 850 350
6 102 Bob 650 250
In the first four rows, the Diff is the same as the Amount because each is the first entry per User per Job (hence the Difference is calculated with reference to a starting Amount of nil in effect).
The last two lines contain information for a User and Job combination that have appeared in the table previously, and hence Diff is calculated as follows:
Job 101 User Pete 850 - 500 = 350
Job 102 User Bob 650 - 400 = 250
I've never had to compare data from rows like this in a SQL query before so don't really know where to start. Any help would be much appreciated.
Added
Please note the Amount is not a running total. It is a subjective assessment made periodically of the value of a User's input in each particular job. It is possible that the Amount could in fact go down from one assessment to the next. What I want is a query that returns the difference between successive assessments 'Amounts'.
Alternative Explanation
I'm looking to return a history trail of movements in the Amount assessed. So another example, looking at a single Job and User is as follows:
Job User Amount Movement
101 Bob 100 100
101 Bob 500 400
101 Bob 400 (100)
101 Bob 1,000 600
However, as per the original example, this information will need to be extracted from a table which contains many Jobs and Users all intermingled.
For SQL Server 2012, try this
This assumes that ID=5 value is wrong in your example
For "previous value" per pair
DECLARE #t TABLE (ID int, Job int, Username varchar(10), Amount int);
INSERT #t
VALUES
(1, 101, 'Bob', 100), (2, 101, 'Pete', 500), (3, 102, 'Bob', 400),
(4, 102, 'Pete', 200), (5, 101, 'Pete', 850), (6, 102, 'Bob', 650);
SELECT
t1.*,
t1.Amount - ISNULL(LAG(Amount) OVER (PARTITION BY Job, Username ORDER BY ID), 0) AS DiffAmount
FROM
#t t1
ORDER BY
t1.ID
For "first value" per pair
SELECT
t1.*,
CASE
WHEN FIRST_VALUE(t1.ID) OVER (PARTITION BY Job, Username ORDER BY ID) = t1.ID THEN t1.Amount
ELSE t1.Amount - FIRST_VALUE(t1.Amount) OVER (PARTITION BY Job, Username ORDER BY ID)
END AS DiffAmount
FROM
#t t1
ORDER BY
t1.ID