why the query is returning every combination - sql

My DBMS is oracle.
I have a table trans with the following column.
Trans_id
Emp_no
From_date
To_date
102
100
2021-05-10
2021-05-16
And an other table time_result with the following columns
Emp_no
Date
W_code
100
2021-05-10
01
100
2021-05-10
02
100
2021-05-10
7.5
100
2021-05-11
08
100
2021-05-12
01
100
2021-05-12
7.5
100
2021-05-13
01
100
2021-05-13
7.5
100
2021-05-14
01
100
2021-05-14
7.5
And another table grade with the following columns
Emp_no
Date
W_code
grade
100
2021-05-10
100
2021-05-11
08
100
2021-05-12
100
2021-05-13
CS
100
2021-05-13
100
2021-05-14
I want this out put
Emp_no
Date
W_code
grade
100
2021-05-10
01
100
2021-05-10
02
100
2021-05-10
7.5
100
2021-05-11
08
100
2021-05-12
01
100
2021-05-12
7.5
100
2021-05-13
01
CS
100
2021-05-13
7.5
100
2021-05-14
01
100
2021-05-14
7.5
In order to achieve this, I have written this query
`
select distinct t.trans_id,
r.emp_no,
r.date,
r.w_code,
g.grade
from trans t
left join time_result r on t.emp_no=r.emp_no
right join grade g on r.date=g.date
`'''
The only problem with this query is, for transaction on 2021-05-13,it’s giving every combination of job grade like this
Trans_id
Emp_no
Date
W_code
grade
102
100
2021-05-10
01
102
100
2021-05-10
02
102
100
2021-05-10
7.5
102
100
2021-05-11
08
102
100
2021-05-12
01
102
100
2021-05-12
7.5
102
100
2021-05-13
01
CS
102
100
2021-05-13
7.5
102
100
2021-05-13
01
102
100
2021-05-13
7.5
CS
102
100
2021-05-14
01
102
100
2021-05-14
7.5
Please advise, in what way the query should be changed to get the desired output.
Any help will be greatly appreciated!
Thanks!!

Related

standard sql: Get customer count and first purchase date per customer and store_id

I use standard sql and I need a query that gets the total count of purchases per customer, for each store_id. And also the first purchase date per customer, for each store_id.
I have a table with this structure:
customer_id
store_id
product_no
customer_no
purchase_date
price
1
10
100
200
2022-01-01
50
1
10
110
200
2022-01-02
70
1
20
120
200
2022-01-02
60
1
20
130
200
2022-01-02
40
1
30
140
200
2022-01-02
60
Current query:
Select
customer_id,
store_id,
product_id,
product_no,
customer_no,
purchase_date,
Price,
first_value(purchase_date) over (partition_by customer_no order by purchase_date) as first_purhcase_date,
count(customer_no) over (partition by customer_id, store_id, customer_no) as customer_purchase_count)
From my_table
This gives me this type of output:
customer_id
store_id
product_no
customer_no
purchase_date
price
first_purchase_date
customer_purchase_count
1
10
100
200
2022-01-01
50
2022-01-01
2
1
10
110
200
2022-01-02
70
2022-01-01
2
1
20
120
210
2022-01-02
60
2022-01-02
2
1
20
130
210
2022-01-02
40
2022-01-02
2
1
30
140
220
2022-01-10
60
2022-01-10
3
1
10
140
220
2022-01-10
60
2022-01-10
3
1
10
140
220
2022-01-10
60
2022-01-10
3
1
10
150
220
2022-01-10
60
2022-01-10
1
However, I want it to look like the table below in its final form. How can I achieve that? If possible I would also like to add 4 colums called "only_in_store_10","only_in_store_20","only_in_store_30","only_in_store_40" for all customer_no that only shopped at that store. It should mark with at ○ on each row of each customer_no that satisfies the condition.
customer_id
store_id
product_no
customer_no
purchase_date
price
first_purchase_date
customer_purchase_count
first_purchase_date_per_store
first_purchase_date_per_store
store_row_nr
1
10
100
200
2022-01-01
50
2022-01-01
2
2022-01-01
1
1
1
10
110
200
2022-01-02
70
2022-01-01
2
2022-01-02
1
1
1
20
120
210
2022-01-02
60
2022-01-02
2
2022-01-02
2
1
1
20
130
210
2022-01-03
40
2022-01-02
2
2022-01-02
2
1
1
30
140
220
2022-01-10
60
2022-01-10
3
2022-01-10
1
1
1
10
140
220
2022-01-11
50
2022-01-11
3
2022-01-11
2
1
1
10
140
220
2022-01-12
40
2022-01-11
3
2022-01-11
2
2
1
10
150
220
2022-01-13
60
2022-01-13
1
2022-01-13
1
1

LAG / OVER / PARTITION / ORDER BY using conditions - SQL Server 2017

I have a table that looks like this:
Date AccountID Amount
2018-01-01 123 12
2018-01-06 123 150
2018-02-14 123 11
2018-05-06 123 16
2018-05-16 123 200
2018-06-01 123 18
2018-06-15 123 17
2018-06-18 123 110
2018-06-30 123 23
2018-07-01 123 45
2018-07-12 123 116
2018-07-18 123 60
This table has multiple dates and IDs, along with multiple Amounts. For each individual row, I want grab the last Date where Amount was over a specific value for that specific AccountID. I have been trying to use the LAG( Date, 1 ) in combination with several variatons of CASE and OVER ( PARTITION BY AccountID ORDER BY Date ) statements but I've had no luck. Ultimately, this is what I would like my SELECT statement to return.
Date AccountID Amount LastOverHundred
2018-01-01 123 12 NULL
2018-01-06 123 150 2018-01-06
2018-02-14 123 11 2018-01-06
2018-05-06 123 16 2018-01-06
2018-05-16 123 200 2018-05-16
2018-06-01 123 18 2018-05-16
2018-06-15 123 17 2018-05-16
2018-06-18 123 110 2018-06-18
2018-06-30 123 23 2018-06-18
2018-07-01 123 45 2018-06-18
2018-07-12 123 116 2018-07-12
2018-07-18 123 60 2018-07-12
Any help with this would be greatly appreciated.
Use a cumulative conditional max():
select t.*,
max(case when amount > 100 then date end) over (partition by accountid order by date) as lastoverhundred
from t;

Trigger created with compilation error

I am trying to create a trigger that increases the discnt of a customer by .04 every time that customer places an order. Next I need to insert a new order in the orders table.
The following is the Customers table:
CID CNAME CITY DISCNT
c001 Tiptop Duluth 10
c002 Basics California 12
c003 7/11 California 8
c004 ACME Duluth 8
c006 ACME Kyoto 0
c007 Goldberg NYC 15
The following is the orders table:
ORDNO MON CID AID PID QTY DOLLARS
1011 jan c001 a01 p01 1000 450
1012 jan c001 a01 p01 1000 450
1019 feb c001 a02 p02 400 180
1017 feb c001 a06 p03 95959 540
1018 feb c001 a03 p04 600 540
1023 mar c001 a04 p05 500 450
1022 mar c001 a05 p06 400 720
1025 apr c001 a05 p07 800 720
1013 jan c002 a03 p03 1000 880
1026 may c002 a05 p03 800 704
1015 jan c003 a03 p05 1200 1104
1014 jan c003 a03 p05 1200 1104
1021 feb c004 a06 p01 1000 460
1016 jan c006 a01 p01 1000 500
1020 feb c006 a03 p07 600 600
1024 mar c006 a06 p01 800 400
The trigger I have created is:
create or replace trigger UpdateDiscnt
after insert or update on orders
for each row
begin
update customers set discnt = 0.4 + :old.discnt where
customers.cid=:new.cid;
end;
/
The error is an oracle error and there is no discnt in the order table so any version of old.discnt is incorrect.
try
create or replace trigger UpdateDiscnt
after insert or update on orders
for each row
begin
update customers set discnt = 0.4 + discnt
where customers.cid= :new.cid;
end;
/

How to add status to the table

I have the following table where is clipping from my db. I have 2 types of contracts.
I: client pays for first 6mth 60$, next 6mth 120$ (111 client)
II: client pays for first 6mth 60$ but if want still pays 60$ the contract will be extended at 6mth, whole contract is 18mth. (321 client who still pays)
ID_Client | Amount | Amount_charge | Lenght | Date_from | Date_to | Reverse
--------------------------------------------------------------------------------
111 60 60 12 2015-01-01 2015-01-31 12
111 60 60 12 2015-02-01 2015-02-28 11
111 60 60 12 2015-03-01 2015-03-31 10
111 60 60 12 2015-04-01 2015-04-30 9
111 60 60 12 2015-05-01 2015-05-31 8
111 60 60 12 2015-06-01 2015-06-30 7
111 120 60 12 2015-07-01 2015-07-31 6
111 120 60 12 2015-08-01 2015-08-31 5
111 120 60 12 2015-09-01 2015-09-30 4
111 120 60 12 2015-10-01 2015-10-31 3
111 120 60 12 2015-11-01 2015-11-30 2
111 120 60 12 2015-12-01 2015-12-31 1
111 120 60 12 2016-01-01 2015-01-31 0
111 120 60 12 2016-02-01 2015-02-29 0
321 60 60 12 2015-01-01 2015-01-31 12
321 60 60 12 2015-02-01 2015-02-28 11
321 60 60 12 2015-03-01 2015-03-31 10
321 60 60 12 2015-04-01 2015-04-30 9
321 60 60 12 2015-05-01 2015-05-31 8
321 60 60 12 2015-06-01 2015-06-30 7
321 60 60 12 2015-07-01 2015-07-31 6
321 60 60 12 2015-08-01 2015-08-31 5
321 60 60 12 2015-09-01 2015-09-30 4
321 60 60 12 2015-10-01 2015-10-31 3
321 60 60 12 2015-11-01 2015-11-30 2
321 60 60 12 2015-12-01 2015-12-31 1
321 60 60 12 2016-01-01 2016-01-30 0
321 60 60 12 2016-02-01 2016-02-31 0
321 60 60 12 2016-03-01 2016-03-30 0
321 60 60 12 2016-04-01 2016-04-31 0
I need to add status column.
A - normal period of agreement
D - where the agreement is doubled after 6mth but after 12mth is E(nd of agreemnt)
E - where contract is finished
L - where contract after 6mth was extended, after 18mth the status will be type E
For 321 Client after 12mth the lenght of contract was updated from 12 to 18
I have a lot of clients so i think better will be using loop to go by all clients?
ID_Client | Amount | Amount_charge | Lenght | Date_from | Date_to | Reverse | Status
-----------------------------------------------------------------------------------------
111 60 60 12 2015-01-01 2015-01-31 12 A
111 60 60 12 2015-02-01 2015-02-28 11 A
111 60 60 12 2015-03-01 2015-03-31 10 A
111 60 60 12 2015-04-01 2015-04-30 9 A
111 60 60 12 2015-05-01 2015-05-31 8 A
111 60 60 12 2015-06-01 2015-06-30 7 A
111 120 60 12 2015-07-01 2015-07-31 6 D
111 120 60 12 2015-08-01 2015-08-31 5 D
111 120 60 12 2015-09-01 2015-09-30 4 D
111 120 60 12 2015-10-01 2015-10-31 3 D
111 120 60 12 2015-11-01 2015-11-30 2 D
111 120 60 12 2015-12-01 2015-12-31 1 D
111 120 60 12 2016-01-01 2015-01-31 0 E
111 120 60 12 2016-02-01 2015-02-29 0 E
321 60 60 12 2015-01-01 2015-01-31 12 A
321 60 60 12 2015-02-01 2015-02-28 11 A
321 60 60 12 2015-03-01 2015-03-31 10 A
321 60 60 12 2015-04-01 2015-04-30 9 A
321 60 60 12 2015-05-01 2015-05-31 8 A
321 60 60 12 2015-06-01 2015-06-30 7 A
321 60 60 12 2015-07-01 2015-07-31 6 L
321 60 60 12 2015-08-01 2015-08-31 5 L
321 60 60 12 2015-09-01 2015-09-30 4 L
321 60 60 12 2015-10-01 2015-10-31 3 L
321 60 60 12 2015-11-01 2015-11-30 2 L
321 60 60 12 2015-12-01 2015-12-31 1 L
321 60 60 18 2016-01-01 2016-01-30 0 L
321 60 60 18 2016-02-01 2016-02-31 0 L
321 60 60 18 2016-03-01 2016-03-30 0 L
321 60 60 18 2016-04-01 2016-04-31 0 L
If the Reverse column is what I think:
update table1 a
set "Status"=
CASE
WHEN A."Reverse" > 6 THEN
'A'
WHEN A."Reverse" > 0 THEN
DECODE (A."Amount", A."Amount_charge", 'L', 'D')
ELSE
CASE
WHEN A."Amount" <> A."Amount_charge" THEN
'E'
ELSE
CASE WHEN ADD_MONTHS ( (SELECT b."Date_from" FROM table1 b WHERE a."ID_Client" = b."ID_Client" AND b."Reverse" = 1),6) > a."Date_from" THEN 'L'
ELSE
'E'
END
END
END
Better is to calculate the sums. The amount per month come from first payment. Something like this:
DECLARE
CURSOR c2
IS
SELECT ID_CLIENT, --AMOUNT, AMOUNT_CHARGE, LENGTH, DATE_FROM, DATE_TO, REVERSE, STATUS,
FIRST_VALUE (amount_charge) OVER (PARTITION BY id_client ORDER BY date_from) first_amount_charge,
SUM (amount) OVER (PARTITION BY id_client ORDER BY date_from) sum_amount,
SUM (amount_charge) OVER (PARTITION BY id_client ORDER BY date_from) sum_amount_charge
FROM TABLE2
FOR UPDATE NOWAIT;
BEGIN
FOR c1 IN c2
LOOP
UPDATE table2
SET status = CASE WHEN c1.sum_amount <= 6 * c1.first_amount_charge THEN 'A'
WHEN c1.sum_amount > 18 * c1.first_amount_charge THEN 'E'
WHEN c1.sum_amount > c1.sum_amount_charge THEN 'D'
ELSE 'L'
END
WHERE CURRENT OF c2;
END LOOP;
END;

SQL- calculating daily stock levels for month as aggregate of availability

I have a table containing following records of stocks from different depots in region. this contains:
itemName
startDate
endDate
quantity
The fields are
key(pk)
itemName- numeric code
startDate- date
endDate- date
amt- number
Sample data with 3 item types
1 101 Jan 1, 2013 Jan 14, 2013 15
2 101 Jan 12, 2013 Jan 15, 2013 3
3 102 Jan 4, 2013 Jan 26, 2013 7
4 102 Jan 6, 2013 Jan 12, 2013 19
5 103 Jan 15, 2013 Jan 16, 2013 3
6 103 Jan 12, 2013 Jan 21, 2013 19
How do I write a query that will get the number of items of each time every day in this period? Essentially I need to have a query that will add up applicable items between startDate and endDate. Thanks
I would want a final query result to look like that would add overlaps for each item
Jan 1 101 15
Jan 1 102 0
Jan 12 101 18
Jan 15 101 3
Jan 16 101 3
while I know i can do for a given date
SELECT item, sum(amt)
FROM [table]
WHERE (date>=startdate) AND (date<=enddate)
GROUP BY item
How do I enable it iterate for the whole month(Jan 1st to 31st) to produce such a report?
Here's what you need to do:
Create a table named [DayNumbers] and fill it with the numbers from 1 through 31:
DayNumber
---------
1
2
3
...
30
31
Now create a saved query in Access named [MonthDates] to create a row for each day in a specified month:
PARAMETERS SelectedYear Long, SelectedMonth Long;
SELECT DateSerial([SelectedYear], [SelectedMonth], DayNumber) AS StatusDate
FROM DayNumbers
WHERE Month(DateSerial([SelectedYear], [SelectedMonth], DayNumber)) = [SelectedMonth];
Note that the WHERE clause restricts the number of days to the actual number of days in the month (e.g., 30 for April).
Create another saved query in Access named [StockStatusRows] to create a row for each day and each item
SELECT StatusDate, itemName
FROM
MonthDates,
(
SELECT DISTINCT itemName FROM StockData
) AS Items;
For test data in [StockStatus] that looks like
key itemName startDate endDate amt
--- -------- ---------- ---------- ---
1 101 2013-01-01 2013-01-14 15
2 101 2013-01-12 2013-01-15 3
3 102 2013-01-04 2013-01-26 7
4 102 2013-01-06 2013-01-12 19
5 103 2013-01-15 2013-01-16 3
6 103 2013-01-12 2013-01-21 19
7 101 2013-01-30 2013-02-03 6
8 102 2013-02-05 2013-02-23 9
9 103 2013-02-07 2013-03-02 11
the [StockStatusRows] query will return
StatusDate itemName
---------- --------
2013-01-01 101
2013-01-02 101
2013-01-03 101
..
2013-01-30 101
2013-01-31 101
2013-01-01 102
2013-01-02 102
2013-01-03 102
...
2013-01-30 102
2013-01-31 102
2013-01-01 103
2013-01-02 103
2013-01-03 103
...
2013-01-30 103
2013-01-31 103
Now we can pull together the actual stock values like so:
SELECT ssr.StatusDate, ssr.itemName, Nz(sums.total, 0) AS TotalOnHand
FROM
StockStatusRows AS ssr
LEFT JOIN
(
SELECT StatusDate, itemName, Sum(amt) AS total
FROM
(
SELECT md.StatusDate, sd.itemName, sd.amt
FROM
StockData sd
INNER JOIN
MonthDates md
ON md.StatusDate>=sd.startDate
And md.StatusDate<=sd.endDate
)
GROUP BY StatusDate, itemName
) AS sums
ON (sums.itemName=ssr.itemName)
AND (sums.StatusDate=ssr.StatusDate)
ORDER BY ssr.StatusDate, ssr.itemName;
returning
StatusDate itemName TotalOnHand
---------- -------- -----------
2013-01-01 101 15
2013-01-01 102 0
2013-01-01 103 0
2013-01-02 101 15
2013-01-02 102 0
2013-01-02 103 0
2013-01-03 101 15
2013-01-03 102 0
2013-01-03 103 0
2013-01-04 101 15
2013-01-04 102 7
2013-01-04 103 0
2013-01-05 101 15
2013-01-05 102 7
2013-01-05 103 0
2013-01-06 101 15
2013-01-06 102 26
2013-01-06 103 0
...
2013-01-12 101 18
2013-01-12 102 26
2013-01-12 103 19
2013-01-13 101 18
2013-01-13 102 7
2013-01-13 103 19
2013-01-14 101 18
2013-01-14 102 7
2013-01-14 103 19
2013-01-15 101 3
2013-01-15 102 7
2013-01-15 103 22
2013-01-16 101 0
2013-01-16 102 7
2013-01-16 103 22
2013-01-17 101 0
2013-01-17 102 7
2013-01-17 103 19
...
2013-01-22 101 0
2013-01-22 102 7
2013-01-22 103 0
...
2013-01-31 101 6
2013-01-31 102 0
2013-01-31 103 0
select itemName from <Table-Name> where startDate>=(start-date) startDate<=(end-date) and endDate>=(start-date) and endDate<=(end-date) group by itemName.
This would calculate the sum of quantities of each product between (start-date) and (end-date).
If you want just total of all items irrespective of their type,
select sum(quantity) from <Table-Name> where startDate>=(start-date) startDate<=(end-date) and endDate>=(start-date) and endDate<=(end-date)
Hope this helps