SQL charge reversal data - sql

I'm extracting financial information, but ran into charge reversal information. Basically if someone was charged for a service there would be a column with that charge. If the charge was later reversed there would be another row with the exact same data, but with a charge reversal flag on it. I want to only get charges that are were not reversed at all.
Below is an example of what i mean and need. As you can see the RVSLInd column has a 1 if the charge is a reversal. The 0 represents an initial charge
I couldn't do: select * from from table where rvslInd = 0. because this would get rid of the reversal row only.
RvslInd|ExtPriceAmt
-------| ----------|
0 | 155.70 |
0 | 1.50 |
0 | 239.00 |
0 | 1111.00 |
1 | -1111.00 |
0 | 217.00 |
0 | 1491.00 |
1 | -1491.00 |
0 | 388.00 |
0 | 72.00 |
This is what I want to be able to get back:
RvslInd|ExtPriceAmt
-------| ----------|
0 | 155.70 |
0 | 1.50 |
0 | 239.00 |
0 | 217.00 |
0 | 388.00 |
0 | 72.00 |
this would be my new table with a customer column added:
CustomerID|RvslInd|ExtPriceAmt
----------|-------| ----------|
1 | 0 | 155.70 |
1 | 0 | 1.50 |
1 | 0 | 239.00 |
2 | 0 | 217.00 |
2 | 0 | 388.00 |
2 | 0 | 72.00 |

Given your data, you cannot reliably do what you want. For the data you have shown, you could do:
select ExtPriceAmt
from t
where RvslInd = 0 and
not exists (select 1 from t t2 where t2.ExtPriceAmt = - t.ExtPriceAmt and t2.RvslInd = 1);
The problem is when the price is repeated. That gets in the way.
That said, all is not hopeless. You can get a list of the prices along with the number of non-reversed times:
select ExtPriceAmt,
sum(case when RvslInd = 0 then 1 when RvslInd = 1 then -1 end) as non_reversed_count
from t
group by ExtPriceAmt
having sum(case when RvslInd = 0 then 1 when RvslInd = 1 then -1 end) > 0;

Related

How to get count based on Values in SQL

I've something to execute I need the count based on values. Here is my Table
"ORD_NUM","ORD_AMOUNT","ORD_DATE","CUST_CODE","AGENT_CODE","ORD_DESCRIPTION"
"200118"|"500"|"07/20/2008"|"C00023"|"A006"|"SOD"
"200120"|"500"|"07/20/2008"|"C00009"|"A002"|"SOD"
"200129"|"1000"|"07/20/2008"|"C00024"|"A006"|"SOD"
"200127"|"1000"|"08/20/2008"|"C00015"|"A003"|"SOD"
"200128"|"500"|"08/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"500"|"09/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"1000"|"09/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"1000"|"10/20/2008"|"C00009"|"A002"|"SOD"
In the order amount we only have either 1000 or 500. We need to return the data count of 500 and 1000 for each date. EX:
Date |1000Count|500Count
07/20/2008| 1 | 2
08/20/2008| 1 | 1
09/20/2008| 1 | 1
10/20/2008| 1 | 1
Thanks! to SlavaRozhnev
select
d,
count(case when amount = 500 then 1 end) count500,
count(case when amount = 1000 then 1 end) count1000
from test
group by d;
Gives Result :
+============+==========+===========+
| d | count500 | count1000 |
+============+==========+===========+
| 2023-01-01 | 4 | 2 |
| 2023-01-02 | 1 | 1 |
| 2023-01-03 | 0 | 1 |
| 2023-01-04 | 1 | 0 |
+------------+----------+-----------+

Running maths over an entire database and ranking all users

I have a database of bets. Each bet has a 'Win', 'Loss', or 'Pending' state. What I want to do is to have an SQL statement that will get the last, say, 20 bets a user has placed, find out their ROI (Total profit / Total staked * 100).
So I'm just wondering if there is a better way to do this. Do I basically have to get the users table, loop over every user, get their last 20 bets, find the ROI and then order it. If my User table gets huge then this process is going to take ages, right?
Is creating a 'View' going to save on this time?
Is there a way to do this in one statement that won't cost my life in processing time?
Here are the tables
Users
| ID | User |
| 1 | Test1 |
| 2 | Test2 |
| 3 | Test3 |
| 4 | Test4 |
Bets
| ID | User | Amount | Odds | Result |
| 1 | 1 | 10 | 1.35 | Win |
| 2 | 1 | 25 | 2.55 | Win |
| 3 | 3 | 15 | 1.65 | Loss |
| 4 | 2 | 11 | 2.12 | Pending |
Se essentially I would like a table that ranks them as ROI.
| User | AmountBet | AmountWon | ROI |
| 1 | 35 | 77 | 215 |
| 2 | 11 | 0 | 0 |
| 3 | 15 | 0 | 0 |
| 4 | 0 | 0 | 0 |
Assuming the ID of the bets table represents increasing time such that it can be used to identify "last 20", then
WITH b
AS
(
SELECT id,
user,
CASE WHEN result = 'Pending' THEN 0 ELSE amount END AS amount,
CASE WHEN result = 'Win' THEN amount * odds ELSE 0 END as winnings,
ROW_NUMBER() OVER (PARTITION BY user ORDER BY id DESC) AS rownum
FROM bets
)
SELECT user,
SUM(amount) AS amount_bet,
SUM(winnings) AS amount_won,
CASE
WHEN SUM(amount) > 0
THEN SUM(winnings) * 100 / SUM(amount)
ELSE 0
END AS roi
FROM b
WHERE rownum < 21
GROUP BY user;
dbfiddle.uk

Comparison error when implementing a MUX gate in nand2tetris

I am trying to implement a MUX (Multiplexor) gate in the nand2tetris course. I first tried myself, and I got an error. But no matter what I changed I always got the error. So I tried checking some code online, and this is what most people use:
CHIP Mux {
IN a, b, sel;
OUT out;
PARTS:
Not(in=sel, out=nsel);
And(a=sel, b=b, out=c1);
And(a=nsel, b=a, out=c2);
Or(a=c1, b=c2, out=out);
}
But even when I try this code I still get the following error:
What I get as a truth table:
| a | b | sel | out |
| 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 1 | 1 | 0 |
What I should get:
| a | b | sel | out |
| 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
| 1 | 1 | 1 | 1 |
I have the newest software suite per 2020-01-13
From what can be seen your input pins are:
a = 0
b = 1
sel = 1
Your internal pins are:
nsel = 1
c1 = 1
c2 = 0
All as expected so far.
Expected out = 1 in this case and you get out = 0. Test script stops at this point because of failure.
Now there might be two reasons of that:
1) you didn't load correct Mux.hdl and because if you calculated Or(c1,c2) you would get 1 which is correct. If you placed And gate in place of Or it would explain failure
2) your implementation of Or.hdl is incorrect.Mux uses your version of Or gate if such file is present in the same directory.
So first verify your code in Hardware Simulator, then verify your implementation of Or.hdl. The latter you could do by removing temporarily Or.hdl from project directory. Hardware Simulator would load built-in version of Or gate.

SQL "Group" and "Count" categories

Edit. This is a follow up from another question. To simplify the question. Assume a table
date | id | type
01/01 | 1 | F
02/01 | 1 | F
02/01 | 1 | F
03/01 | 1 | S
03/01 | 1 | S
04/01 | 1 | F
04/01 | 1 | S
05/01 | 1 | S
I am looking for a way to summarise the above table by combination of transaction types per day. If a person (id) has only one transaction per day it counts as a Single type. If they have more than one it counts as a Multiple one. I've done that with my original query and it works. The output from the above table would be:
date | Single | Multiple
01/01 | 1 | 0
02/01 | 0 | 1
03/01 | 0 | 1
04/01 | 0 | 1
05/01 | 1 | 0
I got that far and it works. What's I'm struggling with (ie. don't have a clue of how to start) is how set up a query to show all possible combinations of Type (SS, FF, FS) instead of just counting the multiple transactions. The desired output would be like:
date | Single | # FF | # FS | # SS
01/01 | 1 | 0 | 0 | 0
02/01 | 0 | 1 | 0 | 0
03/01 | 0 | 0 | 0 | 1
04/01 | 0 | 0 | 1 | 0
05/01 | 1 | 0 | 0 | 0
Any constructive hints or ideas will be much appreciated.
this is assuming that you have max 2 types per date.
You can use the CASE WHEN statement with MIN() and MAX() to check for combination of FF, FS or SS
select [date],
case when count(*) = 1 then 1 else 0 end as Single,
case when count(*) >= 2
and min([type]) = 'F'
and max([type]) = 'F'
then 1
else 0
end as [# FF],
case when count(*) >= 2
and min([type]) = 'F'
and max([type]) = 'S'
then 1
else 0
end as [# FS],
case when count(*) >= 2
and min([type]) = 'S'
and max([type]) = 'S'
then 1
else 0
end as [# SS]
from yourtable
group by [date]
EDIT :
for more then 3 types, just change the count(*) = 2 to count(*) >= 2 as long as the type are either F or S

SQL Query to Count Number of Responses Matching Certain Criteria over a Date Range and Display as Grouped per Day

I have the following set of survey responses in a table.
It's not very clear but the numbers represent the 'satisfaction' level where:
0 = happy
1 = neutral
2 = sad
+----------+--------+-------+------+-----------+-------------------------+
| friendly | polite | clean | rate | recommend | booking_date |
+----------+--------+-------+------+-----------+-------------------------+
| 2 | 2 | 2 | 0 | 0 | 2014-02-03 00:00:00.000 |
| 1 | 2 | 0 | 0 | 2 | 2014-02-04 00:00:00.000 |
| 0 | 0 | 0 | 1 | 0 | 2014-02-04 00:00:00.000 |
| 1 | 1 | 2 | 0 | 2 | 2014-02-04 00:00:00.000 |
| 0 | 0 | 1 | 2 | 1 | 2014-02-04 00:00:00.000 |
| 2 | 2 | 0 | 2 | 0 | 2014-02-05 00:00:00.000 |
| 2 | 1 | 1 | 0 | 2 | 2014-02-05 00:00:00.000 |
| 1 | 0 | 1 | 2 | 0 | 2014-02-05 00:00:00.000 |
| 0 | 1 | 1 | 1 | 1 | 2014-02-05 00:00:00.000 |
| 1 | 0 | 2 | 2 | 0 | 2014-02-05 00:00:00.000 |
+----------+--------+-------+------+-----------+-------------------------+
For each day I need the totals of each of the columns matching each response option. This will answer the question: "How may people answered happy, neutral or sad for each of the available question options".
I would then require a recordset returned such as:
+------------+----------+------------+--------+----------+------------+--------+
| Date | FriHappy | FriNeutral | FriSad | PolHappy | PolNeutral | PolSad |
+------------+----------+------------+--------+----------+------------+--------+
| 2014-02-03 | 0 | 0 | 1 | 0 | 0 | 1 |
| 2014-02-04 | 2 | 2 | 0 | 2 | 1 | 1 |
| 2014-02-05 | 1 | 2 | 2 | 2 | 2 | 1 |
+------------+----------+------------+--------+----------+------------+--------+
This shows that on the 4th two responders answered "happy" for the "Polite?" question, one answered "Neutral" and one answered "sad".
On the 5th, one responder answered "happy" for the Friendly option, two choose "neutral" and two chose "sad".
I really wish to avoid doing this in code but my SQL isn't great. I did have a look around but couldn't find anything matching this specific requirement.
Obviously this is never going to work (nice if it did) but this may help explain:
SELECT cast(booking_date as date) [booking_date],
COUNT(friendly=0) [FriHappy],
COUNT(friendly=1) [FriNeutral],
COUNT(friendly=2) [FriSad]
FROM [u-rate-gatwick-qsm].[dbo].[Questions]
WHERE booking_date >= '2014-02-01'
AND booking_date <= '2014-03-01'
GROUP BY cast(booking_date as date)
Any pointers would be much appreciated.
Many thanks.
Here is a working version of your sample query:
SELECT cast(booking_date as date) as [booking_date],
sum(case when friendly = 0 then 1 else 0 end) as [FriHappy],
sum(case when friendly = 1 then 1 else 0 end) as [FriNeutral],
sum(case when friendly = 2 then 1 else 0 end) as [FriSad]
FROM [u-rate-gatwick-qsm].[dbo].[Questions]
WHERE booking_date >= '2014-02-01' AND booking_date <= '2014-03-01'
GROUP BY cast(booking_date as date)
ORDER BY min(booking_date);
Your expression count(friendly = 0) doesn't work in SQL Server. Even if it did, it would be the same as count(friendly) -- that is, the number of non-NULL values in the column. Remember what count() does. It counts the number of non-NULL values.
The above logic says: add 1 when there is a match to the appropriate friendly value.
By the way, SQL Server doesn't guarantee the ordering of results from an aggregation, so I also added an order by clause. The min(booking_date) is just an easy way of ordering by the date.
And, I didn't make the change, but I think the second condition in the where should be < rather than <= so you don't include bookings on March 1st (even one at exactly midnight).