How to do conversion of units between two tables in SAP HANA Database - sql

Hi I stumble upon some problem with SAP HANA database please note. I have some toy example problem. I tried to come up with solution, but I cannot figure out.
I have two tables one of Volume table
Row MATERIAL BASE_UOM PERIOD SUMMAND
1 55555 KG 201106 99
2 55555 KG 201204 16
3 55555 KG 201301 71
4 55555 KG 201411 83
5 55555 KG 201509 21
6 55555 PAL 201510 64
7 55555 PAL 201511 69
8 55555 KG 201512 55
9 55555 ZRS 201601 81
10 55555 KG 201602 3
11 55555 KG 201603 74
12 55555 KG 201604 58
13 55555 ZRS 201605 8
14 55555 KG 201606 22
The second table is Conversion Table
Row MATERIAL UNIT BASE_UOM UOMN1D UOMZ1D Conversion Rate
1 55555 KG KG 1 1 1
2 55555 CSE KG 1,000.00 2,016.00 2.016
3 55555 ST KG 1,000.00 56 0.056
4 55555 LAY KG 100 3,024.00 30.24
5 55555 PAL KG 100 54,432.00 544.32
6 55555 ZDK KG 59,778.00 54,432.00 0.910569106
7 55555 ZSE KG 59,778.00 54,432.00 0.910569106
8 55555 ZNO KG 59,778.00 54,432.00 0.910569106
9 55555 ZFI KG 59,778.00 54,432.00 0.910569106
10 55555 ZRV KG 1,000.00 57 0.057
11 55555 ZRS KG 1,000.00 2,052.00 2.052
Please bear in mind that Row column is indicative!
Key between tables is MATERIAL column.
I would like to convert all fields in column SUMMAND (Volume table), when there are not KG in BASE_UOM column Volume table e.g. in row 6 is PAL into KG or row 13 ZRS into KG. If we are in situation that we have KG we do not need to update column SUMMAND. To convert PAL into KG I need to look up at Conversion Table at MATERIAL and UNIT Column (look up PAL field) and get row 5 from Conversion Rate column (UOMZ1D/UOMN1D) 544.32*64 (64 is coming from Volume table row 6 Column SUMMAND) and so on. Finally, each individual MATERIAL has its own conversion rate.
The final output of Volume table should look like this. Row 6,7,9,13 is updated correctly.
Row MATERIAL BASE_UOM PERIOD SUMMAND
1 55555 KG 201106 99
2 55555 KG 201204 16
3 55555 KG 201301 71
4 55555 KG 201411 83
5 55555 KG 201509 21
6 55555 PAL 201510 34836.48
7 55555 PAL 201511 37558.08
8 55555 KG 201512 55
9 55555 ZRS 201601 166.212
10 55555 KG 201602 3
11 55555 KG 201603 74
12 55555 KG 201604 58
13 55555 ZRS 201605 16.416
14 55555 KG 201606 22
How I can check for every possible combination to convert all units into KG between this two tables. Would like to suggest me how to scale it, if I have longer list conversion between UNIT and BASE_UOM from Conversion Table imagine like 90 unique possible combinations. What SQL query I need to build in order to achieve the desired output. Any kind of solution are welcome.

Based on your description, you might want to use an inner join to match up the conversion factors to the material.
Something along the lines of this:
SELECT
v.MATERIAL
, v.BASE_UOM as ORIGINAL_UOM
, v.PERIOD
, c.UNIT as TARGET_OUM
, (c.UOMZ1D/c.UOMN1D) * v.SUMMAND as SUMMAND_TARGET_OUM
FROM
VOLUMES v
INNER JOIN CONVERSION c
ON (v.MATERIAL, v.BASE_UOM)
= (c.MATERIAL, c.UNIT)
This query relies on that there is one and only one matching entry in the conversion table for each possible material/base_uom combination.
If no match can be found, the corresponding record from VOLUMES will be omitted in the output.
It's obviously possible to design this more resilient to missing data (e.g. by fall-back output of unchanged data or transitive lookups), but the given solution is straight forward and easy to understand and debug.
Note, that this does not make use of SAP HANA's built-in unit-of-measure conversion functions. As these are designed to replicate the UOM conversion logic of SAP NetWeaver -based applications, these are probably not what you want in this case.

Related

How can I group and get MS Access query to show only rows with a maximum value in a specified field for a consecutive number of times?

I have a large access table that I need to pull specific data from with a query.
I need to get a list of all the IDs that meet a specific criteria, i.e. 3 months in a row with a cage number less than 50.
The SQL code I'm currently working with is below, but it only gives me which months of the past 3 had a cage number below 50.
SELECT [AbBehWeeklyMonitor Database].AnimalID, [AbBehWeeklyMonitor Database].Date, [AbBehWeeklyMonitor Database].Cage
FROM [AbBehWeeklyMonitor Database]
WHERE ((([AbBehWeeklyMonitor Database].Date)>=DateAdd("m",-3,Date())) AND (([AbBehWeeklyMonitor Database].Cage)<50))
ORDER BY [AbBehWeeklyMonitor Database].AnimalID DESC;
I would need it to look at the past 3 months for each ID, and only output if all 3 met the specific criteria, but I'm not sure where to go from here.
Any help would be appreciated.
Data Sample:
Date
AnimalID
Cage
6/28/2022
12345
50
5/19/2021
12345
32
3/20/2008
12345
75
5/20/2022
23569
4
8/20/2022
23569
4
5/20/2022
44444
71
8/1/2012
44444
4
4/1/2022
78986
30
1/20/2022
78986
1
9/14/2022
65659
59
8/10/2022
65659
48
7/14/2022
65659
30
6/14/2022
95659
12
8/14/2022
91111
51
7/14/2022
91111
5
6/14/2022
91111
90
8/14/2022
88888
4
7/14/2022
88888
5
6/14/2022
88888
15
Consider:
Query1:
SELECT AnimalID, Count(*) AS Cnt
FROM Table1
WHERE (((Cage)<50) AND (([Date]) Between #6/1/2022# And #8/31/2022#))
GROUP BY AnimalID
HAVING (((Count(*))=3));
Query2
SELECT Table1.*
FROM Query1 INNER JOIN Table1 ON Query1.AnimalID = Table1.AnimalID
WHERE ((([Date]) Between #6/1/2022# And #8/31/2022#));
Output:
Date AnimalID Cage
6/14/2022 65659 12
7/14/2022 65659 30
8/10/2022 65659 48
6/14/2022 88888 15
7/14/2022 88888 5
8/14/2022 88888 4
Date is a reserved word and really should not use reserved words as names.

I have 3 tables Flight_schedule, Flights and third is Route I need a stored procedure in SQL which give the cheapest flight on a given date

I have 3 tables Flight_schedule, Flights and third is Route I need a stored procedure in SQL which give the cheapest flight on a given date.
When the parameter date is passed to procedure suppose 2 February so the result would be the lowest fare flight on the 2 Feb.
Here is the code where I have joined the tables and passed the parameter to stored procedure but when I am confused in the condition part.
Create proc spCheapestFlight
#FLIGHT_DATE DATE
AS
BEGIN
SELECT Flight_schedule.FlightDate,Flight_schedule.Departure,route.source, route.destination,
Flight_schedule.Arrival
,Flight_schedule.Fare,Flights.Flight_name
FROM Flight_schedule
inner join route ON Flight_schedule.Route_id=route.Route_id inner join
Flights on Flights.Flight_id=Flight_schedule.Flight_id
where Flight_schedule.FlightDate = #FLIGHT_DATE
END
Flight_schedule
F_Id
Flight_id
Total_Fare
FlightDate
Departure
Arrival
Route_Id
Fare
10000
1
1001
2022-02-01
09:30:30.0000000
11:20:45.0000000
100
7500.8
10001
2
1002
2022-02-02
09:45:30.0000000
11:55:45.0000000
101
7000.9
10002
3
1003
2022-02-03
10:30:30.0000000
12:20:45.0000000
102
5111.5
10003
4
1004
2022-02-04
11:30:30.0000000
14:20:45.0000000
103
5500.9
10004
5
1005
2022-02-05
12:30:30.0000000
15:20:45.0000000
104
9000.7
10005
1
1006
2022-02-06
13:30:30.0000000
16:20:45.0000000
105
8675.5
10006
2
1007
2022-02-07
14:30:30.0000000
17:20:45.0000000
106
4000.5
10007
3
1008
2022-02-08
15:30:30.0000000
18:20:45.0000000
107
4100.5
10008
4
1009
2022-02-09
16:30:30.0000000
19:20:45.0000000
101
4000.3
10009
2
1006
2022-02-10
06:30:30.0000000
08:20:45.0000000
108
4000.3
Flights
Flight_id
Flight_name
Capacity
1
Vistara
30
2
Indigo
30
3
SpiceJet
30
4
Go_First
30
5
Air India
30
Route
route_id
source
destination
100
Mumbai
Delhi
101
Delhi
Ahmedabad
102
Ahmedabad
Delhi
103
Ahmedabad
Mumbai
104
Chennai
Mumbai
105
Chennai
Goa
106
Chennai
Delhi
107
Goa
Delhi
108
Bangalore
Delhi
109
Hyderabad
Delhi
your data does not show more than 1 flight per day, in addition there is no need for table Flights and table Route to get result, you should join table FlightSchedule with itself in order to get the minimum fare. your problem can be solve with table-value function(TVF). you should change you PROCEDURE as follows:
CREATE PROCEDURE spCheapest_Costliest_Flight (#FlightDate DATE)
AS
SELECT FS.FlightDate,FS.Departure,route.source, route.destination,
FS.Arrival ,T.Fare,Flights.Flight_name
FROM Flight_schedule FS
inner join route ON FS.Route_id=route.Route_id
inner join Flights on Flights.Flight_id=FS.Flight_id
inner join (select FlightDate FlightDate,MIN(Fare) Fare
from Flight_schedule GROUP BY FlightDate) T
ON T.FlightDate=FS.FlightDate and T.FlightDate=#FlightDate and FS.FlightDate=#FlightDate
GO

In Azure Data bricks I want to get start dates of every week with week numbers from datetime column

This is a sample Data Frame
Date Items_Sold
12/29/2019 10
12/30/2019 20
12/31/2019 30
1/1/2020 40
1/2/2020 50
1/3/2020 60
1/4/2020 35
1/5/2020 56
1/6/2020 34
1/7/2020 564
1/8/2020 6
1/9/2020 45
1/10/2020 56
1/11/2020 45
1/12/2020 37
1/13/2020 36
1/14/2020 479
1/15/2020 47
1/16/2020 47
1/17/2020 578
1/18/2020 478
1/19/2020 3578
1/20/2020 67
1/21/2020 578
1/22/2020 478
1/23/2020 4567
1/24/2020 7889
1/25/2020 8999
1/26/2020 99
1/27/2020 66
1/28/2020 678
1/29/2020 889
1/30/2020 990
1/31/2020 58585
2/1/2020 585
2/2/2020 555
2/3/2020 56
2/4/2020 66
2/5/2020 66
2/6/2020 6634
2/7/2020 588
2/8/2020 2588
2/9/2020 255
I am running this query
%sql
use my_items_table;
select weekofyear(Date), count(items_sold) as Sum
from my_items_table
where year(Date)=2020
group by weekofyear(Date)
order by weekofyear(Date)
I am getting this output. (IMP: I have added random values in Sum)
Week Sum
1 | 300091
2 | 312756
3 | 309363
4 | 307312
5 | 310985
6 | 296889
7 | 315611
But I want in which with week number one column should hold a start date of each week. Like this
Start_Date Week Sum
12/29/2019 1 300091
1/5/2020 2 312756
1/12/2020 3 309363
1/19/2020 4 307312
1/26/2020 5 310985
2/2/2020 6 296889
2/9/2020 7 315611
I am running the query on Azure Data Bricks.
If you have data for all days, then just use min():
select min(date), weekofyear(Date), count(items_sold) as Sum
from my_items_table
where year(Date) = 2020
group by weekofyear(Date)
order by weekofyear(Date);
Note: The year() is the calendar year starting on Jan 1. You are not going to get dates from other years using this query. If that is an issue, I would suggest that you ask a new question asking how to get the first day for the first week of the year.

Get record with maximum value and show other fields from that record

I am trying to show the important dates for a manufacturing process. There are 10 rooms performing the same process. Each time the process starts over a new cycle number is assigned. I want to show the important dates for the current (i.e. maximum) cycle in each room.
So far I have put together a query that will show the important dates for the maximum cycle number overall (my code is below), but I want to add an additional criterion so that I see the information for the maximum cycle number in each room
SELECT
[dbo_batch_overview5].[rm],
[dbo_batch_overview5].[cyc],
[dbo_batch_overview5].[bpr],
[dbo_batch_overview5].[plug_date],
[dbo_batch_overview5].[trig_date],
[dbo_batch_overview5].[flush_date],
[dbo_batch_overview5].[harv_date]
FROM dbo_batch_overview5
WHERE ((([dbo_batch_overview5].[cyc])=(SELECT Max([dbo_batch_overview5].[cyc])
FROM [dbo_batch_overview5]
)));
I think I need to add a GROUP BY statement to specify that I want to see the maximum cycle number for each unique entry in the room [rm] field, here is the code with my attempt at the statement I think I need included:
SELECT
[dbo_batch_overview5].[rm],
[dbo_batch_overview5].[cyc],
[dbo_batch_overview5].[bpr],
[dbo_batch_overview5].[plug_date],
[dbo_batch_overview5].[trig_date],
[dbo_batch_overview5].[flush_date],
[dbo_batch_overview5].[harv_date]
FROM dbo_batch_overview5
WHERE ((([dbo_batch_overview5].[cyc])=(SELECT Max([dbo_batch_overview5].[cyc])
FROM [dbo_batch_overview5]
GROUP BY [dbo_batch_overview5].[rm]
)));
When I try the above code I get an error saying that my subquery is returning more than one value. Can anyone tell me what I'm doing wrong?
As requested, here is some sample data
rm cyc bpr clone_date plug_date trig_date harv_date
1 13 20161031-OP 10/31/2016 11/16/2016 11/22/2016 1/12/2017
1 13 20161101-EV 11/1/2016 11/16/2016 11/22/2016 1/13/2017
1 13 20161031-CG 10/31/2016 11/16/2016 11/22/2016 1/13/2017
1 13 20161101-CB 11/1/2016 11/16/2016 11/22/2016 1/12/2017
1 13 20161031-VO 10/31/2016 11/16/2016 11/22/2016 1/13/2017
1 14 20170104-CG 1/4/2017 1/23/2017 1/28/2017
1 14 20170104-CB 1/4/2017 1/23/2017 1/28/2017
1 14 20170106-AV 1/6/2017 1/23/2017 1/28/2017
1 14 20170106-MN 1/6/2017 1/23/2017 1/28/2017
2 7 20150925-ST 9/25/2015 10/10/2015 10/19/2015 12/16/2015
2 7 20150924-AL 9/24/2015 10/10/2015 10/19/2015 12/16/2015
2 7 20150924-EA 9/24/2015 10/10/2015 10/19/2015 12/21/2015
2 7 20150928-LM 9/28/2015 10/10/2015 10/19/2015 12/22/2015
2 7 20150928-HM 9/28/2015 10/10/2015 10/19/2015 12/19/2015
2 8 20151214-CG 12/14/2015 12/30/2015 1/7/2016 3/14/2016
2 8 20151214-RM 12/14/2015 12/30/2015 1/7/2016 3/15/2016
2 8 20151215-CB 12/15/2015 12/30/2015 1/7/2016 3/8/2016
In the above example, I would only want to see the records associated with cycle 14 in room 1 and cycle 8 in room 2
Would something like this solve your problem?
SELECT
a.[rm],
a.[cyc],
a.[bpr],
a.[plug_date],
a.[trig_date],
a.[flush_date],
a.[harv_date]
FROM dbo_batch_overview5 a
INNER JOIN (SELECT Max([cyc]) AS maxcyc,
rm as rm2
FROM [dbo_batch_overview5]
GROUP BY [rm])c
ON a.rm = c.rm2 AND a.cyc = c.maxcyc

SQL query self join

I am working on a query for a report in Oracle 10g.
I need to generate a short list of each course along with the number of times they were offered in the past year (including ones that weren't actually offered).
I created one query
SELECT coursenumber, count(datestart) AS Offered
FROM class
WHERE datestart BETWEEN (sysdate-365) AND sysdate
GROUP BY coursenumber;
Which produces
COURSENUMBER OFFERED
---- ----------
ST03 2
PD01 1
AY03 2
TB01 4
This query is all correct. However ideally I want it to list those along with COURSENUMBER HY and CS in the left column as well with 0 or null as the OFFERED value. I have a feeling this involves a join of sorts, but so far what I have tried doesn't produce the classes with nothing offered.
The table normally looks like
REFERENCE_NO DATESTART TIME TIME EID ROOMID COURSENUMBER
------------ --------- ---- ---- ---------- ---------- ----
256 03-MAR-11 0930 1100 2 2 PD01
257 03-MAY-11 0930 1100 12 7 PD01
258 18-MAY-11 1230 0100 12 7 PD01
259 24-OCT-11 1930 2015 6 2 CS01
260 17-JUN-11 1130 1300 6 4 CS01
261 25-MAY-11 1900 2000 13 6 HY01
262 25-MAY-11 1900 2000 13 6 HY01
263 04-APR-11 0930 1100 13 5 ST03
264 13-SEP-11 1930 2100 6 4 ST03
265 05-NOV-11 1930 2100 6 5 ST03
266 04-FEB-11 1430 1600 6 5 ST03
267 02-JAN-11 0630 0700 13 1 TB01
268 01-FEB-11 0630 0700 13 1 TB01
269 01-MAR-11 0630 0700 13 1 TB01
270 01-APR-11 0630 0700 13 1 TB01
271 01-MAY-11 0630 0700 13 1 TB01
272 14-MAR-11 0830 0915 4 3 AY03
273 19-APR-11 0930 1015 4 3 AY03
274 17-JUN-11 0830 0915 14 3 AY03
275 14-AUG-09 0930 1015 14 3 AY03
276 03-MAY-09 0830 0915 14 3 AY03
SELECT
coursenumber,
COUNT(CASE WHEN datestart BETWEEN (sysdate-365) AND sysdate THEN 1 END) AS Offered
FROM class
GROUP BY coursenumber;
So, as you can see, this particular problem doesn't need a join.
I think something like this should work for you, by just doing it as a subquery.
SELECT distinct c.coursenumber,
(SELECT COUNT(*)
FROM class
WHERE class.coursenumber = c.coursenumber
AND datestart BETWEEN (sysdate-365) AND sysdate
) AS Offered
FROM class c
I like jschoen's answer better for this particular case (when you want one and only one row and column out of the subquery for each row of the main query), but just to demonstrate another way to do it:
select t1.coursenumber, nvl(t2.cnt,0)
from class t1 left outer join (
select coursenumber, count(*) cnt
from class
where datestart between (sysdate-365) AND sysdate
group by coursenumber
) t2 on t1.coursenumber = t2.coursenumber