Sum over Partition By Only when Value is Greater than 0 - sql

I only want to sum the applied amount when a ledger amount in another table is positive
Example
Table A
Statement # ID
500 1
500 2
500 3
500 4
Table B
Ledger_Amount Type ID
-389.41 Credit 1
-1218.9 Credit 2
-243.63 Credit 3
3485.19 Invoice 4
Table C
Applied_Amount ID
389.41 1
1218.9 2
243.63 3
1633.25 4
The current code is
(sum(applied_amount) over (partition by statement_number),0)
It is coming up with a total of $3485.19 because it is summing by statement number only, and all IDs have the same statement number, the value I want it to come up with is $1633.25 because it should not sum anything where the ledger_amount in table B is less than 0, so ID 1,2,3 should not be summed only valid value is ID 4

There is one approach:
Assuming ID is a unique column, first we should get the IDs we'd work on based on the statementnumber and save them in a temp table:
select Id
into #Ids
from tableA
where StatementNumber=#yourStatementNumber
Then, eliminate the IDs where they have a negative number in table B
Select Id
into #IdsWithPositiveLedger
From #Ids
Where Id in (
Select ID
From tableB
Where Ledger_Amount>0
)
Finally, use the ids left to get your sum:
Select sum(applied_amount)
from tableC
where Id in (select Id from #IdsWithPositiveLedger)

Related

SELECT random 10% of rows for each category on SQL Server

There is a table of products sold.
row_id
customer
product
date_sold
1
customer_1
thingamajig
01.01.2023
2
customer_12
whosi-whatsi
03.01.2023
3
customer_1
watchamacallit
04.01.2023
4
customer_4
whosi-whatsi
06.01.2023
...
...
...
...
There is always one row per one item.
Let's say customer_1 ordered 100 items total. customer_2 ordered 50 items total. customer_3 ordered 17 items total. How do you select random 10% of rows for each customer? The fraction of rows selected should be rounded up (for example 12 rows total results in 2 selected). That means every customer that bought at least one item should appear in the resulting table. In this case the resulting table for customer_1, customer_2 and customer_3 would have 10 + 5 + 2 = 17 rows.
My initial approach would be to create a temp table, calculate desired row counts for each customer and then loop through the temp table and select rows for each customer. Then insert them to another table and select from that one:
drop table if exists #row_counts
select
customer
ceiling(convert(decimal(10, 2), count(product)) / 10) as row_count
into #row_counts
from products_sold
group by customer
-- then use cursor to loop over #row_counts and insert into the final table
-- for randomness an 'order by newid()' will be used
But this just doesn't feel like the right solution...
You need to know total count and a row count of what you want.
Something like this can perhaps be of service:
EDITED due to it not being randomized properly:
select *
from (
select row_number() over(partition by customerid order by newid()) as sortOrder
, COUNT(*) OVER(PARTITION BY customerID) AS cnt
, *
FROM products
) p
-- Now, we want 10% of total count rounded upwards
WHERE sortOrder <= CEILING(cnt * 0.1)

select Query Returns Row Number (Dynamic Number as 1,2,3,4..Sequence) as per Row count

I have table named "Invoice".
ID InvoiceNo invoiceDate main_key
1 100078 10.10.2018 1
2 400058 10.10.2018 1
3 78778 10.10.2018 1
4 78778 10.10.2018 2
5 78778 10.10.2018 1
I need to display data row number in combobox using vb.net, that is, to display only invoice serial number and to add id as valuemember to the combobox.
I tried this
SELECT (
SELECT count(*)
FROM Invoice
WHERE A.ID >= ID
) AS ColumnId
,ID AS ColumnCode
FROM Invoice AS A
WHERE A.main_key = 1
In this table main_key is key to main_table that has buyer and seller data.
While using where condition this query returns wrong sequence of row number.
Please help me guys...Thanks in advance ..!
If you want sequential number within each main_key group, consider:
SELECT (
SELECT count(*)
FROM Invoice
WHERE A.ID >= ID AND A.main_key=main_key
) AS ColumnId
,ID AS ColumnCode
FROM Invoice AS A
WHERE A.main_key = 1;

SQL - Count Results of 2 Columns

I have the following table which contains ID's and UserId's.
ID UserID
1111 11
1111 300
1111 51
1122 11
1122 22
1122 3333
1122 45
I'm trying to count the distinct number of 'IDs' so that I get a total, but I also need to get a total of ID's that have also seen the that particular ID as well... To get the ID's, I've had to perform a subquery within another table to get ID's, I then pass this into the main query... Now I just want the results to be displayed as follows.
So I get a Total No for ID and a Total Number for Users ID - Also would like to add another column to get average as well for each ID
TotalID Total_UserID Average
2 7 3.5
If Possible I would also like to get an average as well, but not sure how to calculate that. So I would need to count all the 'UserID's for an ID add them altogether and then find the AVG. (Any Advice on that caluclation would be appreciated.)
Current Query.
SELECT DISTINCT(a.ID)
,COUNT(b.UserID)
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
GROUP BY a.ID
Which then Lists all the IDs and COUNT's all the USERID.. I would like a total of both columns. I've tried warpping the query in a
SELECT COUNT(*) FROM (
but this only counts the ID's which is great, but how do I count the USERID column as well
You seem to want this:
SELECT COUNT(DISTINCT a.ID), COUNT(b.UserID),
COUNT(b.UserID) * 1.0 / COUNT(DISTINCT a.ID)
FROM a INNER JOIN
b
ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999);
Note: DISTINCT is not a function. It applies to the whole row, so it is misleading to put an expression in parentheses after it.
Also, the GROUP BY is unnecessary.
The 1.0 is because SQL Server does integer arithmetic and this is a simple way to convert a number to a decimal form.
You can use
SELECT COUNT(DISTINCT a.ID) ...
to count all distinct values
Read details here
I believe you want this:
select TotalID,
Total_UserID,
sum(Total_UserID+TotalID) as Total,
Total_UserID/TotalID as Average
from (
SELECT (DISTINCT a.ID) as TotalID
,COUNT(b.UserID) as Total_UserID
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
) x

Trouble performing Postgres group by non-ID column to get ID containing max value

I'm attempting to perform a GROUP BY on a join table table. The join table essentially looks like:
CREATE TABLE user_foos (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
foo_id INT NOT NULL,
effective_at DATETIME NOT NULL
);
ALTER TABLE user_foos
ADD CONSTRAINT user_foos_uniqueness
UNIQUE (user_id, foo_id, effective_at);
I'd like to query this table to find all records where the effective_at is the max value for any pair of user_id, foo_id given. I've tried the following:
SELECT "user_foos"."id",
"user_foos"."user_id",
"user_foos"."foo_id",
max("user_foos"."effective_at")
FROM "user_foos"
GROUP BY "user_foos"."user_id", "user_foos"."foo_id";
Unfortunately, this results in the error:
column "user_foos.id" must appear in the GROUP BY clause or be used in an aggregate function
I understand that the problem relates to "id" not being used in an aggregate function and that the DB doesn't know what to do if it finds multiple records with differing ID's, but I know this could never happen due to my trinary primary key across those columns (user_id, foo_id, and effective_at).
To work around this, I also tried a number of other variants such as using the first_value window function on the id:
SELECT first_value("user_foos"."id"),
"user_foos"."user_id",
"user_foos"."foo_id",
max("user_foos"."effective_at")
FROM "user_foos"
GROUP BY "user_foos"."user_id", "user_foos"."foo_id";
and:
SELECT first_value("user_foos"."id")
FROM "user_foos"
GROUP BY "user_foos"."user_id", "user_foos"."foo_id"
HAVING "user_foos"."effective_at" = max("user_foos"."effective_at")
Unfortunately, these both result in a different error:
window function call requires an OVER clause
Ideally, my goal is to fetch ALL matching id's so that I can use it in a subquery to fetch the legitimate full row data from this table for matching records. Can anyone provide insight on how I can get this working?
Postgres has a very nice feature called distinct on, which can be used in this case:
SELECT DISTINCT ON (uf."user_id", uf."foo_id") uf.*
FROM "user_foos" uf
ORDER BY uf."user_id", uf."foo_id", uf."effective_at" DESC;
It returns the first row in a group, based on the values in parentheses. The order by clause needs to include these values as well as a third column for determining which is the first row in the group.
Try:
SELECT *
FROM (
SELECT t.*,
row_number() OVER( partition by user_id, foo_id ORDER BY effective_at DESC ) x
FROM user_foos t
)
WHERE x = 1
If you don't want to use a sub query based on a composite of all three keys then you need to create a "dense rank" window function field that orders subsets of id, user_id and foo_id by effective date with the rank order field. Then subquery that and take the records where rank_order=1. Since the rank ordering was by effective date you are getting all fields of the record with the highest effective date for each foo and user.
DATSET
1 1 1 01/01/2001
2 1 1 01/01/2002
3 1 1 01/01/2003
4 1 2 01/01/2001
5 2 1 01/01/2001
DATSET WITH RANK ORDER PARTITIONED BY FOO_ID, USER_ID ORDERED BY DATE DESC
1 3 1 1 01/01/2001
2 2 1 1 01/01/2002
3 1 1 1 01/01/2003
4 1 1 2 01/01/2001
5 1 2 1 01/01/2001
SELECT * FROM QUERY ABOVE WHERE RANK_ORDER=1
3 1 1 1 01/01/2003
4 1 1 2 01/01/2001
5 1 2 1 01/01/2001

How to select the biggest value from a list of duplicate entries

i'm trying to query a db which contains a list of transactions. The transactions that i need must be of a specific status and if duplicate cost code are present the query should only return the ID with the highest ID number
my sample table is as follows,
Table name = foo,
status that i need is 3
ID transaction date status cost code
1 20120101 3 5
2 20120101 3 5
3 20120101 4 7
in this example what i need is ID 2
Thanks
select * from foo where status = 3 order by id desc limit 1;
You can replace the 3 with whichever status you're interested in retrieving.
The "order by id desc limit 1" phrase will satisfy the "ID with the highest ID number" constraint.
You can use MAX to get the highest ID number if the selected columns are same
SELECT transaction_date, Status, cost_code, MAX(ID) As ID
FROM foo
GROUP BY transaction_date, Status, cost_code
Use this query:
SELECT MAX(ID) AS MaxID
FROM foo
WHERE status = 3