How to statistics sales, city, customer of goods use oracle - sql

I have a oracle view, and include the sale of goods details. It like this:
OrderId OrderDetailId GoodsId GoodsName UnitName SalesQty Price CustomerName Country City
200138 ddd0a3b42adb 770 A bag 5 18.00 AAAA USA NewYork
223448 70ca7ceb41c7 193 D bottle 10 10.00 BBB USA NewYork
200118 ab472857573e 1286 F cup 8 50.00 CCC China Beijing
244028 230a43920667 770 A bag 20 18.00 CCC China Beijing
251118 118fc2b3839b 5929 C box 40 6.00 DDDD Japan Tokyo
200000 abd0a3b42ddd 770 A bag 15 18.00 AAAA USA NewYork
111118 11111113839b 5929 C box 40 6.00 FFFF Japan Tokyo
And I want a SQL statement statistics sales, the number of cities, the number of customers of each goods. The result should be like this:
GoodsId GoodsName SalesQty(UnitName) CityQty CustomerQty
GoodsId GoodsName SalesQty(UnitName) CityQty CustomerQty
770 A 40(bag) 2 2
193 D 10(bottle) 1 1
1286 F 8(cup) 1 1
5929 C 80(box) 1 2
How to write sql statistical statement? Thanks!

Simply use GROUP BY
select GoodsId, GoodsName, UnitName,
sum(SalesQty) SalesQty,
count(distinct City) CityQty,
count(distinct CustomerName) CustomerQty
from goods_view
group by GoodsId, GoodsName, UnitName
demo

You may use cube, to include also sub&grand totals of quantities :
select GoodsId, GoodsName||'('||UnitName||')' GoodsName,
sum(SalesQty) SalesQty, count(distinct City) CityQty, count(distinct CustomerName) CustomerQty
from v_goods
group by cube(GoodsId, GoodsName||'('||UnitName||')')
order by GoodsId,GoodsName||'('||UnitName||')';

Related

Query with sum functions

for a little project(hobby purpose) i am building a C# application with a SQL database behind it.
However I am trying to build a query with a sum function which calculates values from a different table.
Here are the relevant tables and sample data
Hotel table
Id, Name Adress Zipcode Phone
1 Ankunding Group 90 Shelley Terrace 649-6326 86-(672)239-5855
2 Gerlach-Gutmann 50776 Bartillon Road 27109 CEDEX 33-(412)226-8055
3 Breitenberg-Smith 3289 Talisman Avenue 59762 86-(141)636-8780
4 Smitham-Marks 5 Veith Plaza 216282 7-(400)484-7233
5 Beatty LLC 3 Center Pass 940028 212-(310)974-4364
Reservation table
id, customerid, Startdate Enddate Amount of persons
1 163 2016-06-19 2017-04-30 4
2 172 2016-12-02 2016-08-18 5
3 162 2017-01-20 2017-04-08 3
4 66 2017-04-06 2017-01-07 2
5 104 2017-05-07 2016-09-10 2
RoomReservation table
Roomid, reservationid
3 53
3 198
4 178
5 172
5 218
Room table
id, hotelid, Roomnumber, price
1 1 1.01 268.83
2 1 1.02 201.28
3 1 1.03 126.64
4 1 1.04 122.56
5 1 1.05 217.41
Now I am trying to make a query to which gives me an overview off income per hotel. So for each hotel I want to get the reservations, and do amount of persons * the price of the room for each room in the hotel.
I've tried different things without success, I read somewhere that I needed to use a subquery but I have no idea how.
I want it to look like;
Hotelname1; income
Hotelname2; income
Hotelname3; income
Hotelname4; income
Hotelname4; income
Why can't you just do this:
SELECT
Hotel.Name,
SUM(Room.Price*Reservation.Amountofpersons)
FROM
Hotel
JOIN Room
ON Hotel.HotelId=Room.HotelId
JOIN RoomReservation
ON Room.RoomId=RoomReservation.RoomId
JOIN Reservation
ON RoomReservation.ReservationId=Reservation.ReservationId
GROUP BY
Hotel.Name
You can try it whit this query:
select hotel.name,sum(reservation.amount*room.price)
from hotel_table as hotel
inner join room_table as room on (hotel.hotelid=room.hotelid)
inner join roomreservation_table as room_reservation on (room.roomid=room_reservation.roomId)
inner join reservation_table as reservation on (room.reservationId=reservation.reservationid)
group by hotel.hotelid

Stored Procedure Select from 3 tables

I have three tables in my database Sales, SalesPeople and Appliances.
Sales
SaleDate EmployeeID AppID Qty
---------- ---------- ----- -----------
2010-01-01 1412 150 1
2010-01-05 3231 110 1
2010-01-03 2920 110 2
2010-01-13 1412 100 1
2010-01-25 1235 150 2
2010-01-22 1235 100 2
2010-01-12 2920 150 3
2010-01-14 3231 100 1
2010-01-15 1235 300 1
2010-01-03 2920 200 2
2010-01-31 2920 310 1
2010-01-05 1412 420 1
2010-01-15 3231 400 2
SalesPeople
EmployeeID EmployeeName CommRate BaseSalary SupervisorID
---------- ------------------------------ ----------- ----------- ------------
1235 Linda Smith 15 1200 1412
1412 Anne Green 12 1800 NULL
2920 Charles Brown 10 1150 1412
3231 Harry Purple 18 1700 1412
Appliances
ID AppType StoreID Cost Price
---- -------------------- ------- ------------- -------------
100 Refrigerator 22 150 250
110 Refrigerator 20 175 300
150 Television 27 225 340
200 Microwave Oven 22 120 180
300 Washer 27 200 325
310 Washer 22 280 400
400 Dryer 20 150 220
420 Dryer 22 240 360
How can I obtain this result? (That displays the profitability of each of the salespeople ordered from the most profitable to the least. Gross is simply the sum of the quantity of items sold multiplied by the price. Commission is calculated from the gross minus the cost of those items (i.e. from
qty*(price-cost)). Net profit is the total profit minus commission.)
Name Gross Commission Net Profit
------------- ----- ---------- ---------
Charles Brown 2380 83.5 751.5
Linda Smith 1505 83.25 471.75
Harry Purple 990 65.7 299.3
Anne Green 950 40.2 294.8
My attempt:
CREATE PROC Profitability AS
SELECT
sp.EmployeeName, (sum(s.Qty) * a.Price) as [Gross],
[Gross] - a.Cost, as [Commision],
SOMETHING as [Net Profit]
FROM
Salespeople sp, Appliances a, Sales s
WHERE
s.AppID = a.ID
AND sp.EmployeeID = s.EmployeeID
GROUP BY
sp.EmployeeName
GO
EXEC Profitability
Simple rule: Never use commas in the FROM clause. Always use explicit JOIN syntax.
In addition to fixing the JOIN syntax, your query needs a few other enhancements for the aggregation functions:
SELECT sp.EmployeeName, sum(s.Qty * a.Price) as Gross,
SUM(s.Qty * (a.Price - a.Cost)) * sp.CommRate / 100.0 as Commission,
SUM(s.Qty * (a.Price - a.Cost)) * (1 - sp.CommRate / 100.0) as NetProfit
FROM Sales s JOIN
Salespeople sp
ON sp.EmployeeID = s.EmployeeID JOIN
Appliances a
ON s.AppID = a.ID
GROUP BY sp.EmployeeName sp.CommRate
ORDER BY NetProfit DESC;

How to make right outer join?

I am using OE schema and trying to see item # and quantity on hand in each warehouse and if any warehouse does not have item than it should show 0 item in hand. i am running following SQL and it is not showing 0 quantity for items.
select i.product_id,w.warehouse_name ,(i.quantity_on_hand)
from inventories i
right outer join warehouses w
on (i.warehouse_id=w.warehouse_id)
order by 1
I want to see result like this:
PRODUCT_ID WAREHOUSE_NAME NVL(I.QUANTITY_ON_HAND,0)
---------- ----------------------------------- -------------------------
2262 Sydney 35
2262 Beijing 50
2262 Bombay 35
2262 San Francisco 155
2262 Seattle, Washington 77
Toronto 0
New Jersey 0
Southlake, Texas 0
Mexico City 0
3501 Toronto 220
3501 Sydney 320
3501 Mexico City 294
3501 Beijing 268
3501 San Francisco 353
New Jersey 0
Southlake, Texas 0
Seattle, Washington 0
Bombay 0
You want to see a row for every warehouse and every product. So, start with generating this list and use left outer join to bring in the values that exist:
select i.product_id, w.warehouse_name, coalesce(i.quantity_on_hand, 0)
from warehouses w cross join
(select distinct product_id from inventories) p left join
inventories i
on w.warehouse_id = i.warehouse_id and p.product_id = i.product_id
order by i.product_id, w.warehouse_name;

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

Extract selective records

I have a table like this:
Table A
Customer InvoiceNo Region Type Amount
A001 10001 Europe FG 100
B001 10002 Asia FG 200
C001 10003 America MISC 50
D001 10004 Asia FG 300
A001 10005 Europe MISC 20
C001 10006 America MISC 10
B001 10007 Asia FG 300
I wish to split the Amount into 2 columns, namely Sales_Amt & Misc. The Region is not required.
The result that I wish to have should look like this:
Customer InvoiceNo Type Sales_Amt MISC
A001 10001 FG 100 0
B001 10002 FG 200 0
C001 10003 MISC 0 50
D001 10004 FG 300 0
A001 10005 MISC 0 20
C001 10006 MISC 0 10
B001 10007 FG 300 0
Thanks.
That's pretty simple:
select
Customer,
InvoiceNo,
Type,
decode(Type, 'MISC', 0, 1) * Amount as Sales_Amt,
decode(Type, 'MISC', 1, 0) * Amount as Misc
from
TableA
;
Select Customer,InvoiceNo,Type,
Case when TYPE!='MISC' Then amount Else 0 End as Sales_Amt,
Case when TYPE='MISC' Then amount Else 0 End as Misc
From TabalA