SQL Coding for Logical Operators question - sql

Q:
Using the retail. Inventory table, calculate what the total inventory would be for each product with 5 or less items in stock if all of the items on order were delivered immediately without any other sales taking place. The product_id for each product should be the first column in your results.
I need a sql code the one I am using is not working and I dont know another way to get the result my professor is asking for.
Expected:
product_id ?column?
3 20
4 37
6 13
8 4
10 24
24 41
31 4
41 35
42 2
58 25
71 28
this is what I am using, but like I said it's wrong:
select product_id
from retail.inventory
where total_on_hand <= 5;

SELECT product_id, SUM(quantity_on_hand + quantity_on_order) AS total_inventory
FROM retail.inventory
WHERE quantity_on_hand + quantity_on_order <= 5
GROUP BY product_id
This query first selects the product_id and calculates the total inventory for each product by adding the quantity_on_hand and quantity_on_order columns. It then filters the results to only include products with 5 or less items in stock, and finally groups the results by product_id to calculate the total inventory for each product.

SELECT product_id, SUM(quantity_on_hand + quantity_on_order) AS total_inventory_name
FROM retail_inventory_tablename
WHERE quantity_on_hand <= 5
GROUP BY product_id
You may try above

Took this class - the answer is:
SELECT product_id, total_on_hand + total_on_order
FROM retail.inventory
WHERE total_on_hand <= 5

Related

SQL Sum with conditions in two columns

I'm very new to SQL and VB.NET. I have an existing table called STOCK with the columns shown here, and I want to sum buy and sell to display current quantity.
Existing table:
ID
Date
BUY
SELL
Current quantity
1
01/01/22
88
0
2
03/01/22
22
0
94669
05/02/22
0
30
I want to display in Current quantity like this
(the current quantity amount in the row above + BUY - SELL)
I add result in Current quantity manually, but I want to do this in automatic way it is possible in SQL code
ID
Date
BUY
SELL
Current quantity
1
01/01/22
88
0
88
2
03/01/22
22
0
110
3
05/02/22
0
30
80
You can try this:
select a.*,
sum(net_sell) over (order by Curr_date ) as Current_quantity
from
(select s.*,
buy-sell as net_sell
from stock s) a ;
Dbfiddle link : https://dbfiddle.uk/?rdbms=postgres_11&fiddle=196a41a578d1e699ccaa3e878e261019

Get count of repeat visits

I have a very simple question that's doing my head in, so I'm turning to stackoverflow for it to be cleared.
I have some category ids on a website, and user_ids. A user_id can visit a category several time, as is shown in the example below.
I want my query to return the number of repeat visitors per category (=visited more than once): e.g. for category 113 it's 2 repeat visitors (user_ids 6 and 5 visited/occur more than once) over a total of 7 total visitors. The idea is to calculate a repeat visit rate (here would be 2/7).
Somehow, my mind is stumped about this. Would appreciate any help, thanks :)
category_id
user_id
113
6
113
6
113
5
113
5
113
1
113
7
113
6
120
11
120
11
120
9
Many thanks!
You can use two levels of aggregation:
select category_id,
sum(case when cnt > 1 then 1 else 0 end) as num_repeat_users
from (select category_id, user_id, count(*) as cnt
from t
group by category_id, user_id
) cu
group by category_id;

SQL How to calculate Average time between Order Purchases? (do sql calculations based on next and previous row)

I have a simple table that contains the customer email, their order count (so if this is their 1st order, 3rd, 5th, etc), the date that order was created, the value of that order, and the total order count for that customer.
Here is what my table looks like
Email Order Date Value Total
r2n1w#gmail.com 1 12/1/2016 85 5
r2n1w#gmail.com 2 2/6/2017 125 5
r2n1w#gmail.com 3 2/17/2017 75 5
r2n1w#gmail.com 4 3/2/2017 65 5
r2n1w#gmail.com 5 3/20/2017 130 5
ation#gmail.com 1 2/12/2018 150 1
ylove#gmail.com 1 6/15/2018 36 3
ylove#gmail.com 2 7/16/2018 41 3
ylove#gmail.com 3 1/21/2019 140 3
keria#gmail.com 1 8/10/2018 54 2
keria#gmail.com 2 11/16/2018 65 2
What I want to do is calculate the time average between purchase for each customer. So lets take customer ylove. First purchase is on 6/15/18. Next one is 7/16/18, so thats 31 days, and next purchase is on 1/21/2019, so that is 189 days. Average purchase time between orders would be 110 days.
But I have no idea how to make SQL look at the next row and calculate based on that, but then restart when it reaches a new customer.
Here is my query to get that table:
SELECT
F.CustomerEmail
,F.OrderCountBase
,F.Date_Created
,F.Total
,F.TotalOrdersBase
FROM #FullBase F
ORDER BY f.CustomerEmail
If anyone can give me some suggestions, that would be greatly appreciated.
And then maybe I can calculate value differences (in percentage). So for example, ylove spent $36 on their first order, $41 on their second which is a 13% increase. Then their second order was $140 which is a 341% increase. So on average, this customer increased their purchase order value by 177%. Unrelated to SQL, but is this the correct way of calculating a metric like this?
looking to your sample you clould try using the diff form min and max date divided by total
select email, datediff(day, min(Order_Date), max(Order_Date))/(total-1) as avg_days
from your_table
group by email
and for manage also the one order only
select email,
case when total-1 > 0 then
datediff(day, min(Order_Date), max(Order_Date))/(total-1)
else datediff(day, min(Order_Date), max(Order_Date)) end as avg_days
from your_table
group by email
The simplest formulation is:
select email,
datediff(day, min(Order_Date), max(Order_Date)) / nullif(total-1, 0) as avg_days
from t
group by email;
You can see this is the case. Consider three orders with od1, od2, and od3 as the order dates. The average is:
( (od2 - od1) + (od3 - od2) ) / 2
Check the arithmetic:
--> ( od2 - od1 + od3 - od2 ) / 2
--> ( od3 - od1 ) / 2
This pretty obviously generalizes to more orders.
Hence the max() minus min().

Return rows where specific number is reached for the first time (postgres)

Have hit a roadblock.
Context: am using PostgreSQL 9.5.8
I have a table, as follows, with customers' points accrued. The table has multiple rows per customer as it records every change in points (like an event table). i.e. customer 1 may buy 1 item and accrue 10 points which is one row, then on another day spend some of these points and be left with 5 points which is another row, and then purchase another item and accrue a further 10 bringing them back up to 15 which displays as another row. Each of these rows with point amounts has a created_at column.
Example table:
Customer ID created_at no_points row
123 17/09/2017 5 1
123 09/10/2017 8 2
124 10/10/2017 12 3
123 10/10/2017 15 4
125 12/10/2017 12 5
126 17/09/2017 6 6
123 11/10/2017 11 7
123 12/10/2017 9 8
127 17/09/2017 5 9
124 11/10/2017 5 10
125 13/10/2017 5 11
123 13/10/2017 12 12
I want to track the first time a customer reaches a certain threshold i.e. >= 10 points. It doesn't matter how much they go over 10 points, the only criteria is that I select the first time the customer reaches this threshold. I would also like this query to fetch only rows where the customer has reached the threshold of 10 for the first time in the last week.
Following these rules, in the above example, I would like my query to select rows 3, 4 and 5.
I have tried the following query:
SELECT x.id,
min(x.created_at)
FROM (
SELECT
p.id as id,
p.created_at as created_at,
p.amount as amount
FROM "points" p
WHERE p.amount >= 10 ) x
WHERE x.created_at >= (now()::date - 7)
AND x.created_at < now()::date
GROUP BY x.id
I'm unsure that I'm retrieving the right thing however from the result set I am seeing & the results set is huge so it's not evident. Could someone sense check?
Thanks in advance.
Use cumulative functions:
select p.*
from (select p.*,
sum(num_points) over (partition by p.customer_id order by p.created_at) as cume_num_points
from points p
) p
where cume_num_points >= 10 and
(cume_num_points - num_points) < 10;
EDIT:
I may have misunderstood the question. If you just want the first break, one method uses window functions:
select p.*
from (select p.*,
lag(num_points) over (partition by p.customer_id order by p.created_at) as prev_num_points
from points p
) p
where num_points >= 10 and
prev_num_points < 10;
Or, without a subquery:
select distinct on (p.customer_id) p.*
from customers p
where num_points >= 10
order by p.customer_id, p.created_at;

How to get primary key of selected column in row in SQL Server 2012

I have the below table. I want to select 30 pieces of Product Code 011A from the table. Each row contains a number of pieces, in the column PCS. I want to select the 30 pieces in FIFO order based on date, and return the number of pieces selected from each row, so I'll need to know the primary key value for each row that has pieces selected from it. For example, from this data:
Key Product Code PCS Date
1 011A 10 2015-07-01
2 011B 20 2015-07-01
3 011C 20 2015-07-01
4 011A 12 2015-07-02
5 011A 40 2015-07-03
6 011D 60 2015-07-04
7 011A 20 2015-07-04
Selecting 30 pieces of product code "011A" should give an output table like:
Key Product Code PCS DATE
1 011A 10 2015-07-01
4 011A 12 2015-07-02
5 011A 8 2015-07-03
You can see that the total number of pieces is 30, and that the maximum number of pieces were selected from the rows with primary key 1 and 4, because they're the first dates. Only 8 were selected from row #5, because it's the next in date order, and only 8 is needed to reach 30 total. Row #7 wasn't needed, so it doesn't show up in the result.
How can I write a query to accomplish this?
In SQL Server 2012, you can use cumulative sum:
select t.*
from (select t.*,
sum(pcs) over (partition by productcode order by date) as cumepcs
from thetable t
where productcode = '011A'
) t
where cumepcs - pcs < 30;
Doing a cumulative sum in SQL Server 2008 is a bit more work. Here is one way:
select t.*
from (select t.*,
(select sum(t2.pcs)
from thetable t2
where t2.productcode = t.productcode and
t2.date <= t.date
) as cumepcs
from thetable t
where productcode = '011A'
) t
where cumepcs - pcs < 30;
EDIT:
If you want the allocated amounts from each bucket, you need to tweak the size of the last bucket. Change the select to:
select t.*,
(case when cume_pcs <= 30 then pcs
else 30 - (cumepcs - pcs)
end) as allocated_pcs
. . .