How do I create a table that displays Current Inventory based on the location of said Inventory using Pl/SQL? - plsql

Here is what I have:
product location quantity moved dttm
apple shop1 30 null '08/10/22'
orange shop1 20 null '08/15/22'
pear shop1 40 null '08/20/22'
apple shop2 10 shop1 '08/22/22'
orange shop3 15 shop1 '08/22/22'
Where Location is the current location of product, with that quantity, and moved is the previous location of the inventory (which is sometimes null if it is being added to the system), and dttm the date that change occurred.
I'm looking for a way to show the current inventory based changes made to the data set. The view Should look something like the below:
Location Product Quantity
shop1 apple 20
shop1 orange 5
shop1 pear 40
shop2 apple 10
shop3 orange 15
What is the best practice for making a view this way? I have yet to come up with a working query that gives accurate numbers. I have the side that adds inventory to a location working (using an outer apply statement. I'm getting hung up on how to get my move column to substract inventory from products at a given location.
This answer seems to be close to what I want, but with the added complexity of location also being a factor in the totals for the items.
What am I missing? or does my dataset need to be remade to accomplish what I want?
Thanks for any and all help

Here's one option: create a view (or a subquery, or use a CTE - as I did) as union of locations (either as the original locations, or moved ones), and the rest is then easy - a simple aggregation.
Sample data:
SQL> with test (product, location, quantity, moved) as
2 (select 'apple' , 'shop1', 30, null from dual union all
3 select 'orange' , 'shop1', 20, null from dual union all
4 select 'pear' , 'shop1', 40, null from dual union all
5 select 'apple' , 'shop2', 10, 'shop1' from dual union all
6 select 'orange' , 'shop3', 15, 'shop1' from dual
7 ),
Query begins here:
8 temp as
9 (select location, product, quantity from test
10 union all
11 select moved , product, -quantity from test where moved is not null
12 )
13 select location, product, sum(quantity) quantity
14 from temp
15 group by location, product
16 order by location, product
17 /
LOCAT PRODUC QUANTITY
----- ------ ----------
shop1 apple 20
shop1 orange 5
shop1 pear 40
shop2 apple 10
shop3 orange 15
SQL>

Related

Query to get current remaining stock in sqlite

I have a table named stock:
name stock
------------
a 100
b 200
c 50
and a sales table
name sale
--------------------
a 30
c 20
d 30
The result should be:
name stock
-----------------
a 70
b 200
c 20
d -30
Please tell me the sqlite query for this.
My query:
select a.name, a.stock - b.sales as stock
from stock as a
inner join Sale as b on a.name = b.name
but how to get those name which doesn't exists in stock but exists in sales?
I believe the following will do what you want :-
SELECT name, sum(stock) - sum(sold) FROM
(
SELECT name, sold, 0 as stock FROM sales
UNION ALL
SELECT name, 0 AS sold, stock FROM stock
)
GROUP BY name
ORDER BY name
Basically the inner SELECT extracts a table with 3 columns name, sold and stock for each combination and with 0 as the missing value. i.e. :-
This is then used as the source of the outer SELECT which groups according to name summing the sales and the stock and subtracting the sales from the stock as per :-

How to set all values for a column to a max value on a certain WHERE?

If I have:
2 baskets of oranges with 7 and 10 each
3 baskets of peaches with 12 and 15 each
then I want to set:
for every orange basket value of maxfruit to 10 and
for every peach basket value of maxfruit to 15
I tried
update baskets set maxfruit = (select max(fruitCount) from baskets b where b.fruit = fruit)
but it just sets everything to 15...
In SQL, when you are referencing a column by its name, the table instance that you end up with is the innermost one, unless you use a table prefix.
So fruit refers to the innermost instance, b. This means that b.fruit and fruit are always the same value.
To refer to the outer table instance, you must use the name of the outer table:
update baskets
set maxfruit = (select max(fruitCount)
from baskets b
where b.fruit = baskets.fruit);
^^^^^^^^
(And instead of b.fruit, you could write just fruit, but that could be unclear.)
your update is just pulling the max from the whole table you can use a sub query to pull out the max for each fruit
UPDATE b
SET b.maxfruit = b2.fruitCount
FROM baskets b
INNER JOIN (SELECT fruit, MAX(fruitCount) AS fruitCount
FROM baskets
GROUP BY fruit) b2 ON b.fruit = b2.fruit

SAS Counting Occurrences based on multiple layers within set time period

I am trying to count occurrences where the same person was billed for an item, four or more times, by the same place within 30 days of each instance. For example, input would look something like:
person service place date
A x shop1 01/01/15
A x shop1 01/15/15
A x shop1 01/20/15
B y shop2 03/20/15
B y shop2 04/01/15
C z shop1 05/05/15
And output would look something like:
person service place date count
A x shop1 01/01/15 3
A x shop1 01/15/15 3
A x shop1 01/20/15 3
B y shop2 03/20/15 2
B y shop2 04/01/15 2
C z shop1 05/05/15 1
I have tried stuff similar to:
data work.want;
do _n_ =1 by 1 until (last.PLACE);
set work.rawdata;
by PERSON PLACE;
if first.PLACE then count=0;
count+1;
end;
frequency= count;
do _n_ = 1 by 1 until (last.PLACE);
set work.rawdata;
by PERSON PLACE;
output;
end;
run;
this gives a count based on person and place but does not factor in time. Any help or suggestions would be greatly appreciated! Thank you
This can be done easily with proc sql...
Your data:
data have;
input person $ service $ place $;
datalines;
A x shop1
A x shop1
A x shop1
B y shop2
B y shop2
C z shop1
;
run;
Then we count the occurences of "place" for each 1,2 group, and join the original table.
proc sql;
create table want as
select a.*, b._count
from have as a
inner join
(
select person, service, count(place) as _count
from have
group by 1,2
) as b
on a.person = b.person
and a.service = b.service
;
quit;
Is there a date field? We need it in order to group the data by month (or 30 days), for example.
proc sql;
create table summary as
select person, service, place, count(*) as count
from rawdata
group by person, service, place
having count>=4;
quit;
Note: This doesn't check to see if the events occurred within 30 days of each other. I didn't know the type of data you had for this in your dataset.

need help to build a query that takes the dynamic column name return by another query as record

I have 2 tables:
Employee_tbl
empid empname empsalary emplocation
----- ------- --------- ------------
1 santhosh 15000 East godavari
2 Srinivas 25000 Westgodavari
3 sandeep 35000 Hyderabad
4 prathap 55000 Hyderabad
5 praveen 45000 West godavari
configuration_tbl
config_id column_name
--------- -----------
1 empid
2 empname
3 empsalary
4 emplocation
When I pass input as config_id it should display the values from that column.
Ex: If I pass config_id then it should display all empname from employee_tbl.
When there is only a limited number of columns I advice you to use a SQL with a case statement. Depending on whether you want to fold numbers into one text field or not, you may need two case columns. Execute immediate is possible but has additional overhead.

I can not just join it because I need to group DVDs by movie_id first? - ORACLE

I have this query that has no problem:
SELECT m.movie_name, cd.times_requested
FROM movie m,
(select *
from(
select movie_id, count(movie_id) as times_requested
from movie_queue
where status_id=0 or status_id=1
group by movie_id
) ab
where times_requested>1) cd
WHERE m.movie_id=cd.movie_id;
It returns the following list.
MOVIE_NAME TIMES_REQUESTED
----------------------------------------------------------------------
E.T. the Extra-Terrestrial 2
Indiana Jones and the Kingdom of the Crystal Skull 2
War of the Worlds 3
Unbreakable 3
Question:
How do I add another column showing the amount of DVDs available for each movie, I can not just join it because I need to group DVDs by movie_id first?.
Table above is OK, but I want to add a third column, the third column will contain information about the number of DVDs available for each movie. the problem is that the number of dvds is stored in another table call DVDS. The structure of the table DVDs is similar to this:
DVD_ID MOVIE_ID DVD_ENTRY_DATE
---------- ---------- --------------
1 1 24-JUL-12
2 1 24-JUL-12
3 1 24-JUL-12
4 2 24-JUL-12
5 2 24-JUL-12
Desired Result:
Final table should look similar to the one below:
MOVIE_NAME TIMES_REQUESTED DVDS_AVAILABLE
-------------------------------------------------------------------
E.T. the Extra-Terrestrial 2 3
Indiana Jones and the Kingdom 2 1
War of the Worlds 3 3
Unbreakable 3 1
I tried the following code, but did not get the result I wanted
I am assuming I need to go to dvd table first and find all dvds that match the movie_id I want and group them by movie_id. I tried the code below, but instead of returning the 4 rows I want it is returning 72.
SELECT m.movie_name, pomid.times_requested, d.dvds_available
FROM movie m,
(select *
from(
select movie_id, count(movie_id) as times_requested
from movie_queue
where status_id=0 or status_id=1
group by movie_id
) mid
where times_requested>1) pomid,
(select movie_id, count(movie_id) as dvds_available
from dvd
group by movie_id) d
WHERE m.movie_id=pomid.movie_id;
Thanks for your suggestions in how to fix this.
A join to d.movie_id is missing, that's why you get too many rows. (Quick check: how many tables do I have? How many joins do I have?)
And I'd also add an outer join to get all movies, even when there are no dvd or movie_queue entries.
SELECT m.movie_name
,NVL(pomid.times_requested,0) times_requested
,NVL(d.dvds_available,0) dvds_available
FROM movie m
,(SELECT *
FROM (SELECT movie_id
,COUNT (movie_id) AS times_requested
FROM movie_queue
WHERE status_id = 0
OR status_id = 1
GROUP BY movie_id) mid
WHERE times_requested > 1) pomid
,(SELECT movie_id
,COUNT (movie_id) AS dvds_available
FROM dvd
GROUP BY movie_id) d
WHERE m.movie_id = pomid.movie_id(+)
AND d.movie_id(+) = pomid.movie_id;
http://www.sqlfiddle.com/#!4/5437a/11
Not sure I really understand your table structure, but this might get you started:
select movie_id,
sum(case when status_id in (0,1) then 1 else 0 end) as times_requested,
count(movie_id) as dvd_available,
from movie_queue
group by movie_id;

Resources