How to use sum function in a subquery? - sql

I am using a IBM DB2 DBMS and I would like to show the total amount paid per client. Currently when I select all, it will show me multiple pay amounts per clients and this leads to repeating clients.
I would like to show the total amount paid per client, against an arbitrary number that is not in my table.
This is what I have thus far. I am getting an error with my subquery.
SELECT T1.CLIENT_ID
(SELECT SUM(T2.PAY_AMT) FROM AR_SUM T2 WHERE T1.CLIENT_ID = T2.CLIENT_ID) AS TOTAL
FROM AR_SUM T1
GROUP BY CLIENT_ID
FETCH FIRST 100 ROWS ONLY
I would like it to show:
Client_ID TOTAL
abc 100
def 200
ghi 150
As I mentioned earlier, I would like to compare that to an arbitrary goal amount that is not in my table. Also, is there a way to translate that to a percentage?
My end product I would like:
Client_ID TOTAL percent of total <-- (lets say out of 100)
abc 10 .10 or 10% <-- if possible
def 20 .2
ghi 15 .15

As written, your query is missing a comma:
SELECT T1.CLIENT_ID,
-------------------^
(SELECT SUM(T2.PAY_AMT)
FROM AR_SUM T2
WHERE T1.CLIENT_ID = T2.CLIENT_ID) AS TOTAL
FROM AR_SUM T1
GROUP BY CLIENT_ID
FETCH FIRST 100 ROWS ONLY;
But it is simpler to use an aggregation function:
SELECT T.CLIENT_ID, SUM(T.PAY_AMT) AS TOTAL
FROM AR_SUM T
GROUP BY t.CLIENT_ID
FETCH FIRST 100 ROWS ONLY;

Related

PostgreSQL, SQL: how to use rows values as parameters in a ready-made function?

Is it possible to use rows in a table as parameters in a function?
For example, I have a simple function that calculates total sales by amount and quantity.
SELECT sales from public.my_function(v_amount, v_qty)
I have a table with two columns: sum and quantity
Amount QTY
100 5
200 10
300 20
400 30
500 40
I want to add another column where there will be a function result for parameters that are in each row.
I try to place columns within a function but it returns me an error.
It seems to me that my try is really wrong:
SELECT Amount,
QTY
(select sales from public.my_function(select Amount from public.table, select QTY from public.table) as Sales
FROM public.table
Result need as :
Amount QTY Sales
100 5 500
200 10 2000
300 20 6000
400 30 12000
500 40 20000
Is there a way to do it right?
Thanks
You want to use a lateral join if the function returns a table:
SELECT Amount, QTY, x.Sales
FROM public.table t cross join lateral
public.my_function(t.amount, t.qty) x;
If it just returns a scalar, then you don't have to do anything special:
SELECT t.Amount, t.QTY,
public.my_function(t.amount, t.qty) as Sales
FROM public.table t;

Calculate percentages of columns in Oracle SQL

I have three columns, all consisting of 1's and 0's. For each of these columns, how can I calculate the percentage of people (one person is one row/ id) who have a 1 in the first column and a 1 in the second or third column in oracle SQL?
For instance:
id marketing_campaign personal_campaign sales
1 1 0 0
2 1 1 0
1 0 1 1
4 0 0 1
So in this case, of all the people who were subjected to a marketing_campaign, 50 percent were subjected to a personal campaign as well, but zero percent is present in sales (no one bought anything).
Ultimately, I want to find out the order in which people get to the sales moment. Do they first go from marketing campaign to a personal campaign and then to sales, or do they buy anyway regardless of these channels.
This is a fictional example, so I realize that in this example there are many other ways to do this, but I hope anyone can help!
The outcome that I'm looking for is something like this:
percentage marketing_campaign/ personal campaign = 50 %
percentage marketing_campaign/sales = 0%
etc (for all the three column combinations)
Use count, sum and case expressions, together with basic arithmetic operators +,/,*
COUNT(*) gives a total count of people in the table
SUM(column) gives a sum of 1 in given column
case expressions make possible to implement more complex conditions
The common pattern is X / COUNT(*) * 100 which is used to calculate a percent of given value ( val / total * 100% )
An example:
SELECT
-- percentage of people that have 1 in marketing_campaign column
SUM( marketing_campaign ) / COUNT(*) * 100 As marketing_campaign_percent,
-- percentage of people that have 1 in sales column
SUM( sales ) / COUNT(*) * 100 As sales_percent,
-- complex condition:
-- percentage of people (one person is one row/ id) who have a 1
-- in the first column and a 1 in the second or third column
COUNT(
CASE WHEN marketing_campaign = 1
AND ( personal_campaign = 1 OR sales = 1 )
THEN 1 END
) / COUNT(*) * 100 As complex_condition_percent
FROM table;
You can get your percentages like this :
SELECT COUNT(*),
ROUND(100*(SUM(personal_campaign) / sum(count(*)) over ()),2) perc_personal_campaign,
ROUND(100*(SUM(sales) / sum(count(*)) over ()),2) perc_sales
FROM (
SELECT ID,
CASE
WHEN SUM(personal_campaign) > 0 THEN 1
ELSE 0
end AS personal_campaign,
CASE
WHEN SUM(sales) > 0 THEN 1
ELSE 0
end AS sales
FROM the_table
WHERE ID IN
(SELECT ID FROM the_table WHERE marketing_campaign = 1)
GROUP BY ID
)
I have a bit overcomplicated things because your data is still unclear to me. The subquery ensures that all duplicates are cleaned up and that you only have for each person a 1 or 0 in marketing_campaign and sales
About your second question :
Ultimately, I want to find out the order in which people get to the
sales moment. Do they first go from marketing campaign to a personal
campaign and then to sales, or do they buy anyway regardless of these
channels.
This is impossible to do in this state because you don't have in your table, either :
a unique row identifier that would keep the order in which the rows were inserted
a timestamp column that would tell when the rows were inserted.
Without this, the order of rows returned from your table will be unpredictable, or if you prefer, pure random.

SQL counting query

Sorry if this is a basic question.
Basically, I have a table that is as follows, below is a basic sample
store-ProdCode-result
13p I10x 5
13p I20x 7
13p I30x 8
14a K38z 23
17a K38z 23
my data set has nearly 100,000 records.
What I'm trying to do is, for every store find the top 10 prodCode.
I am unsure of how to do this but what I tried was:
select s_code as store, prod_code,count (prod_code)
from top10_secondary
where prod_code is not null
group by store,prod_code
order by count(prod_code) desc limit 10
this is giving me something completely different and i'm unsure on how I go about achieving my final result.
All help is appreciated.
Thanks
The expected output should be: for every store(s_code) display the top 10 prodcode
so:
store--prodcode--result
1a abc 5
1a abd 4
2a dgf 1
2a ldk 6
.(10 times until next store code)
You can use the table twice in the FROM clause, once for the data, and once to get a count of how many records have fewer results for that store.
SELECT a.s_code, a.prod_code, count(*)
FROM top10_secondary a
LEFT OUTER JOIN top10_secondary b
ON a.s_code = b.s_code
AND b.result < a.result
GROUP BY a.s_code, a.prod_code
HAVING count(*) < 10
With this technique though, you may get more than 10 records per store if the 10th result value exists multiple times. Because the limit rule is simply "include record as long as there are less than 10 records with result values than mine"
It looks like in your case, "result" is a ranking, so they would not be duplicated per store.
This is a good case for Window functions.
SELECT
s_code,
prod_code,
prod_count
FROM
(
SELECT
s_code,
prod_code,
prod_count,
RANK() OVER (PARTITION BY s_code ORDER BY prod_Count DESC) as prod_rank
FROM
(SELECT s_code as store, prod_code, count(prod_Code) prod_count FROM table GROUP BY s_code, prod_code) t1
) t2
WHERE prod_rank <= 10
The inner most query gets the count of each product at the store. The second inner more query determines the rank for those products for each store based on that count. Then the outer most query limits the results based on that rank.
o

MS Access query table without primary key

Claim# Total ValuationDt
1 100 1/1/12
2 550 1/1/12
1 2000 3/1/12
2 100 4/1/12
1 2100 8/1/12
3 200 8/1/12
3 250 11/1/12
Using MS Access, I need a query that returns only claims which have been valuated greater than $500 at some point in that claim's life time. In this example, the query should return
Claim# Total ValuationDt
1 100 1/1/12
2 550 1/1/12
1 2000 3/1/12
2 100 4/1/12
1 2100 8/1/12
because claim# 1 was valuated greater than $500 on 3/1/12, claim# 2 was valuated greater than $500 on 1/1/12, and claim# 3 was never valuated greater than $500.
You can use IN:
SELECT *
FROM Table1
WHERE Claim IN (SELECT Claim
FROM Table1
WHERE Total > 500)
Sql Fiddle Demo
Try this:
Select * from table where claim in (Select claim from table where total > 500)
Here table is the name of your table.
This could be the solution
SELECT distinct *
FROM YourTableName
WHERE claim# IN (SELECT DISTINCT claim#
FROM YourTableName
WHERE total > 500)
ORDER BY 3;
Optionally order by
This should work
Select DISTINCT Claim FROM yourtable Where Total > 500
EDIT:
In the case that my initial answer does not fulfill your requirements, then you can use a sub-query. A subquery is a query inside your query (nested queries). The reason we have to do it like that is because if you use something like
Select * FROM yourtable Where Total > 500
Then the result set would only be those moments where the total of the claim was higher than 500, but it would not indicate other moments where it was less or equal than 500.
Therefore, as others have stated, you use a subquery like:
SELECT *
FROM Table1
WHERE Claim IN (SELECT Claim
FROM Table1
WHERE Total > 500)
Note: see that there is a query after the IN keyword, so we have nested queries (or subquery if you prefer).
Why does it work? well, because:
SELECT Claim
FROM Table1
WHERE Total > 500
Will return every claim (only the number of the claim) in which the total was greater than 500 at some point. Therefore, this query will return 1 and 2. If you substitute that in the original query you get:
SELECT *
FROM Table1
WHERE Claim IN (1, 2)
Which will get you every column of every row with Claim numbers equal to either 1 or 2.
You can identify which [Claim#] values satisfy your condition ...
SELECT DISTINCT [Claim#]
FROM YourTable
WHERE [Total] > 500
If that was correct, use it as a subquery which you INNER JOIN to your table, to restrict the result set to only those claims.
SELECT y.[Claim#], y.[Total], y.[ValidationDt]
FROM YourTable AS y
INNER JOIN
(
SELECT DISTINCT [Claim#]
FROM YourTable
WHERE [Total] > 500
) AS sub
ON y.[Claim#] = sub.[Claim#];
Compare this approach vs. the IN() suggestions and see whether you notice any difference in execution speed.
You should be able to use
SELECT [Claim#],[Total],[ValidationDt]
FROM yourtable
WHERE [Claim#] IN (SELECT [Claim#]
FROM yourtable
WHERE Total >= 500)
Should return all values >= 500 for any ValidationDt.

display the row with the first and last odd number

good day everyone . I've been searching for a long time for the activity that our professor wants us to do .
for example my column name is tax, tax has these values:
TAX
-----
3681
4292
4895
1894
1127
the program should show numbers 3681 and 1127 . any response is much appreciated . btw our school is using MS SQL Server 2000 .
From my understanding of your question, you are looking for the rows with the lowest or highest odd number as the last character? If so, then this should work:
select t.tax
from yourtable t
join (
select min(right(tax,1)) minoddchar, max(right(tax,1)) maxoddchar
from yourtable
where tax % 2 = 1 --ensure odd result
) t2 on right(t.tax,1) in (t2.minoddchar, t2.maxoddchar)
SQL Fiddle Demo
SELECT MIN(tax), Max(tax)
FROM Table
WHERE tax %2 <> 0
Demo: SQL Fiddle
If you actually want first and last from your unordered list, it's a trickier proposition and results could be inconsistent, since without a value to ORDER BY you can't guarantee order. Would usually use ROW_NUMBER(), but not available in 2000, if that's what you're after there are options, the easiest would be to do:
SELECT Tax, IDENTITY(1,1) as TaxID
INTO Table2
FROM Table1
SELECT (SELECT TOP 1 Tax FROM Table2 WHERE Tax %2 <> 0 ORDER BY TaxID)
,(SELECT TOP 1 Tax FROM Table2 WHERE Tax %2 <> 0 ORDER BY TaxID DESC)
You can use this:
SELECT tax FROM Table ORDER BY tax.id ASC LIMIT 1
UNION
SELECT tax FROM Table ORDER BY tax.id DESC LIMIT 1
or this:
SELECT MIN(tax.id), tax FROM Table
UNION
SELECT MAX(tax.id), tax FROM Table
select tax from Table fetch first 1 row only;
select tax from table fetch last 1 row only;