Recursion in Prolog and more - recursion

I have this knowledgebase in prolog of a air company and their flighs:
flight(departure,arrive,day).
flight(london,paris,monday).
flight(paris,barcelona,thursday).
flight(paris,madrid,sunday).
flight(madrid,lisbon,saturday).
recursive rules:
connection(Departure,Arrive):-flight(Departure,Arrive,Day).
connection(Departure,Arrive):-flight(Departure,X,Day),connection(X,Arrive).
And with this I can ask the question: is there a connection possible between london and barcelona?
question: connection(london,barcelona).
And the answer will be afirmative.
But is there any rules / questions I can do that it could give me more details ?
for example: the connection between london and barcelona is direct or indirect ?
other question: I would like to know when the flight is indirect, which city is in the middle ? (in the example above it would be "paris" for example.
can anyone help me figure it out?

I created the simple program which uses days.
In the sample program, I assume three days.
waiting_days( 3 ). /* acquire the specified day of the week. For example 3 day from monday -> monday, tuesday, wednesday */
Please adjust the days of waiting_days.
And, I made other corrections.
I checked the following programs by SWI-Prolog and LPA Prolog.
/* flight_city(london,barcelona, monday). */
weekday( [sunday, monday, tuesday, wednesday, thursday, friday, saturday] ).
waiting_days( 3 ). /* acquire the specified day of the week. For example 3 day monday -> monday, tuesday, wednesday */
flight_city( Departure, Arrive, Day ) :-
connection(Departure, Arrive, Day, []).
connection(Departure, Arrive, Day, City_list) :-
flight(Departure, Arrive, Flight_Day),
not( member( Departure, City_list ) ),
waiting_days_get( Day, Days ),
member( Flight_Day, Days ),
% !,
append( [Arrive, Departure], City_list, City_list2 ),
reverse( City_list2, City_list3 ),
write_city_list( City_list3 ),
fail.
connection(Departure,Arrive, Day, City_list ) :-
flight(Departure,X,Flight_Day),
/* Prevention of an infinite loop */
not( member( Departure, City_list ) ),
waiting_days_get( Day, Days ),
member( Flight_Day, Days ),
append( [Departure], City_list, City_list2 ),
connection(X, Arrive, Flight_Day, City_list2 ).
direct_check( 2, _, [] ) :- !.
direct_check( Citys_number, [_ | Result], Middle ) :-
2 < Citys_number, !,
middle_get( Result, Middle ).
direct_check( _, _, _ ) :- fail.
middle_get( [_], [] ) :- !.
middle_get( [First | Result], [First | Result2] ) :-
middle_get( Result, Result2 ).
waiting_days_get( Today, Days ) :-
weekday( Weekday ),
waiting_days( Count ),
( 7 < Count -> Count2 is 7;
Count2 is Count
),
waiting_days_get_this_week( Weekday, Today, Count2, This_week_days ),
length( This_week_days, Num2 ),
Count3 is Count2 - Num2,
waiting_days_get_next_week( Count3, Weekday, Next_week_days ),
append( This_week_days, Next_week_days, Days ).
waiting_days_get_this_week( [Today |Result ], Today, Count, Days ) :-
!,
waiting_days_get_main( Count, [Today | Result], Days ).
waiting_days_get_this_week( [_ | Result], Today, Num, Days ) :-
waiting_days_get_this_week(Result, Today, Num, Days ).
waiting_days_get_main( 0, _, [] ) :- !.
waiting_days_get_main( _, [], [] ) :- !.
waiting_days_get_main( Count, [Day | Result], [Day |Result2 ] ) :-
Count2 is Count - 1,
waiting_days_get_main( Count2, Result, Result2 ).
waiting_days_get_next_week( 0, _, [] ) :- !.
waiting_days_get_next_week( Count, [First | Result], [First | Days] ) :-
Count2 is Count - 1,
waiting_days_get_next_week( Count2, Result, Days ).
write_city_list( City_list3 ) :-
length( City_list3, Citys_number ),
direct_check( Citys_number, City_list3, Middle ),
write( City_list3 ), nl,
( Citys_number == 2 -> write( 'direct' ), nl, nl;
write( 'indirect' ), nl,
write( Middle ), nl, nl
), !.
flight(london,paris,monday).
flight(paris,barcelona,thursday).
flight(paris,madrid,sunday).
flight(madrid,lisbon,saturday).
flight(london,tokyo,monday).
flight(tokyo, paris, monday).
flight(london,barcelona,monday).
flight(london,lisbon,monday).
flight(lisbon,barcelona,monday).
flight(tokyo,london,monday).

Related

SSMS Case Statement With Multiple Fields

I have a case statement to sum, round and label amounts that works fine, but the data ends up in horizontal format (multiple money amounts per record), causing me to do an unpivot in a subsequent statement to format the data vertically (one money amount per record). I would like to accomplish this in one statement if possible. My code is as follows:
SELECT
Field,
ROUND(SUM(CASE
WHEN TYPE = 'Paid Loss'
THEN AMOUNT
ELSE 0
END
), 2
) PAID,
ROUND(SUM(CASE
WHEN TYPE = 'OS'
THEN AMOUNT
ELSE 0
END
), 2
) OS,
ROUND(SUM(CASE
WHEN TYPE <> 'Paid Exp'
THEN AMOUNT
ELSE 0
END
), 2
) INCURRED
FROM dbo.mydatabase
GROUP BY Field;
The result is:
Field |PAID |OS |INCURRED
----------------------------
result1 | 1 | 20 | 10
result2 | 5 | 30 | 15
When what I really want is:
Field | DATA_TYPE | AMOUNT
---------------------------
result1 | PAID | 1
result2 | PAID | 5
result3 | OS | 20
result4 | OS | 30
result5 | INCURRED | 10
result6 | INCURRED | 15
Keys will be unique so that isn't an issue. Anyone know how to rearrange the CASE so this can be done in one statement? Thanks!
Wouldn't this work?
SELECT Field, 'PAID' DATA_TYPE, ROUND(SUM(AMOUNT), 2) AMOUNT
FROM dbo.mydatabase
WHERE TYPE = 'Paid Loss'
GROUP BY Field
UNION ALL
SELECT Field, 'OS' DATA_TYPE, ROUND(SUM(AMOUNT), 2) AMOUNT
FROM dbo.mydatabase
WHERE TYPE = 'OS'
GROUP BY Field
UNION ALL
SELECT Field, 'INCURRED' DATA_TYPE, ROUND(SUM(AMOUNT), 2) AMOUNT
FROM dbo.mydatabase
WHERE TYPE <> 'Paid Exp'
GROUP BY Field
or even like this:
SELECT Field
, (CASE
WHEN TYPE IN ('Paid Loss', 'OS') THEN TYPE
WHEN TYPE <> 'Paid Exp' THEN 'INCURRED'
END) DATA_TYPE
, ROUND(SUM(AMOUNT), 2) AMOUNT
FROM dbo.mydatabase
GROUP BY Field
, (CASE
WHEN TYPE IN ('Paid Loss', 'OS') THEN TYPE
WHEN TYPE <> 'Paid Exp' THEN 'INCURRED'
END) DATA_TYPE

Calculate first day and last day of week of current month

I want to calculate first date and last date of a week for the current month given current datetime.
For example, 01 December 2017 is first day and 02 December 2017 is last day of week for that week for the month of December. In the same week of year, 26 November 2017 is first day of week and
30 November 2017 is last day of week for previous month.
So if today is 01 December 2017, I should get 01-02 from current datetime , instead of 26-02 range.
PS: I am trying to do this thing in a query of Sqlite. I want to group some values on a weekly basis. The days of the week should belong to current month. Hence this requirement. Till now this is my query.
SELECT SUM(amount) as Y,
strftime('%d', datetime(createdOn/1000, 'unixepoch'), '-'||strftime('%w', datetime(createdOn/1000, 'unixepoch'))||' day' )
||'-'||
strftime('%d', datetime(createdOn/1000, 'unixepoch'), '+'||(6-strftime('%w', datetime(createdOn/1000, 'unixepoch')))||' day' ) AS X
FROM my_table
GROUP BY strftime('%d', datetime(createdOn/1000, 'unixepoch'), '-'||strftime('%w', datetime(createdOn/1000, 'unixepoch'))||' day' )
||'-'||
strftime('%d', datetime(createdOn/1000, 'unixepoch'), '+'||(6-strftime('%w', datetime(createdOn/1000, 'unixepoch')))||' day' )
How to achieve that; given current datetime.
Common table expressions are useful to hold intermediate results:
WITH t1 AS (
SELECT amount, date(createdOn / 1000, 'unixepoch', 'localtime') AS date
FROM my_table
),
t2 AS (
SELECT *,
date(date, 'weekday 6') AS end_of_week,
date(date, 'weekday 6', '-6 days') AS start_of_week
FROM t1
),
t3 AS (
SELECT *,
strftime('%m', date ) AS month,
strftime('%m', start_of_week) AS sowk_month,
strftime('%m', end_of_week ) AS eowk_month,
date(date, 'start of month') AS start_of_month,
date(date, '+1 month', 'start of month', '-1 day') AS end_of_month
FROM t2
),
t4 AS (
SELECT *,
CASE WHEN sowk_month = month THEN start_of_week
ELSE start_of_month
END AS week_in_month_start,
CASE WHEN eowk_month = month THEN end_of_week
ELSE end_of_month
END AS week_in_month_end
FROM t3
),
t5 AS (
SELECT amount,
week_in_month_start || '-' || week_in_month_end AS week_in_month
FROM t4
)
SELECT SUM(amount) AS Y,
week_in_month
FROM t5
GROUP BY week_in_month;

Using Case statement with multiple when in Teradata

Suppose I have a data table with the following fields:
CUSTOMER: either A or B
DAY: either Monday or Tuesday
PAID: either Y or N
The total number of rows being four, let's say the data table is this:
CUSTOMER DAY PAID
A Monday Y
A Tuesday N
B Monday Y
B Tuesday N
How do I create a SQL query on Teradata SQL Assistant, that will show the number of people who were Y on Monday and N on Tuesday? (or any of these combinations) I tried to use the query below, but cannot seem to figure out the logic. Your help is much appreciated!
SELECT DAY,
COUNT(CASE PAID WHEN 'Y' THEN CUSTOMER ELSE 0 END) AS PAID_CUSTOMERS,
COUNT(CASE WHEN PAID = 'Y' AND DAY = 'Monday' AND DAY = 'Tuesday' AND PAID = 'N' THEN CUSTOMER ELSE 0 END) AS CUSTOMERS_YM_NT
FROM T1
GROUP BY 1
ORDER BY 1
So, break each day down into a separate case statement:
case when DAY = 'Monday' and PAID = 'NO' then 'NO' else 'YES' end as Monday,
case when DAY = 'Tuesday' and PAID = 'NO' then 'NO' else 'YES end as Tuesday,
etc
Then, you can wrap that with another select and apply whatever criteria you want:
select
<whatever columns>
from
(select
case when DAY = 'Monday' and PAID = 'NO' then 'NO' else 'YES' end as Monday,
case when DAY = 'Tuesday' and PAID = 'NO' then 'NO' else 'YES end as Tuesday,
...
) t
where Monday 'YES'
and Tuesday = 'YES'

The query performance is very low + correlated subquery

The query's aim is to get reserved rooms status is 3 or going to reserve in 30 to 45 minutes status in 2 or unreserved status in 1. reservation rooms are in RESEENH table and each reservation is in ORD_NOARCHIVE table which has begintime and endtime of reservation. So for each reservation room this query checks whether reservation is available at current time also its checks the meeting room parents and children. if children is reserved then parents are are blocked.
it takes 10 secs to fetch first 50 records.
with cte as
(
SELECT DISTINCT R.syscode,
R.behcode,
R.syscode AS FK_RESERVATIONUNIT, (
CASE
WHEN R.TYPE = 3 THEN '1'
WHEN R.TYPE = 1 THEN '2'
ELSE NULL
END ) AS LOCATION_TYPE,
R.sysobjalg AS FK_PROPERTY,
MP.syscode AS FK_MEASUREMENTPOINT,
MP.fk_plc_occupancy_state AS FK_PLC_OCCUPANCY_STATE,
F.syscode AS FK_FLOOR,
R.transitiontime,
r.type,
r.is_compoundreservationunit,
r.is_archived,
MP.fk_person,
os.transitionperiod
FROM reseenh R
--left outer join ordtrantbl RSS
--ON RSS.reservationunisyscode = R.syscode
left outer join objond F
ON F.syscode = R.fk_floor
left outer join pln_measurementpoint MP
ON MP.fk_reservationunit = R.syscode
AND MP.is_primary_measurement_point = 'T',
pln_ordersetting os
)
select cte.syscode,cte.behcode,cte.FK_RESERVATIONUNIT,
(CASE
WHEN O.begindatetime_user IS NULL THEN '1' --GREEN
WHEN O.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440 ) > current_date THEN '2' -- ORANGE
WHEN O.begindatetime_user + (Nvl(cte.transitiontime, ( cte.transitionperiod )) /1440 ) > current_date THEN '3' -- RED
ELSE '3'
END ) AS LOCAVAILABILITY_STATUS_CODE,
cte.LOCATION_TYPE,
cte.FK_PROPERTY,
Coalesce(O.sysmelder, cte.fk_person) AS FK_PERSON,
O.syscode AS FK_ORDER,
O.ref_bostate_userdefined AS FK_ORDER_STATE_USER,
O.fk_bostate AS FK_ORDER_STATE_SYSTEM,
FK_MEASUREMENTPOINT,FK_PLC_OCCUPANCY_STATE,FK_FLOOR
from cte left outer join ord_noarchive O on O.syscode in
( SELECT MAX(ord.syscode) KEEP (DENSE_RANK FIRST ORDER BY ord.begindatetime_user) OVER (PARTITION BY ord.sysreseenh )
FROM ord_noarchive ORD
WHERE ( ( (
current_date >= ( ORD.begindatetime_user - ( Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440) )
AND (
current_date - ( Nvl(cte.transitiontime, (cte.transitionperiod )) / 1440 ) ) <=ORD.enddatetime_user )
OR ( (
current_date + ( (
CASE
WHEN (
cte.TYPE = 1 ) THEN 30
ELSE 45
END ) / 1440 ) ) >= ( ORD.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod))/1440 ) )
AND (
current_date - ( Nvl(cte.transitiontime, ( cte.transitionperiod )) / 1440 ) ) < ORD.enddatetime_user ) )
AND ORD.sysreseenh IN
(
SELECT fk_reservationunit_parent
FROM pln_reservationunit_rut
WHERE fk_reservationunit_child IN
(
SELECT fk_reservationunit_child
FROM pln_reservationunit_rut
WHERE cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode)
UNION
SELECT cte.syscode
FROM dual
UNION
SELECT
CASE
WHEN cte.is_compoundreservationunit = 'T' THEN fk_reservationunit_child
ELSE fk_reservationunit_parent
END
FROM pln_reservationunit_rut
WHERE (
cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode )
OR (
cte.is_compoundreservationunit = 'F'
AND fk_reservationunit_child = cte.syscode ))
AND ORD.fk_bostate IN
(
SELECT syscode
FROM pln_bostate
WHERE pnname IN ( 'Requested',
'Made',
'AdministrativelyCompleted' )
AND fk_bodefinition = ref_bodefinition)
AND ORD.sysreseenh = O.sysreseenh
))
WHERE cte.is_archived = 'F'
AND cte.TYPE IN ( 1,
3 )
AND cte.fk_floor=495
No time to analyze the details of a very complex query, but my overall sense is that you are trying to do too many things at once. Separate the tasks. Check on room availability in one query, and check on the children/parent thing in a separate query.
Also, you could analyze the execution plan for the query and see what it bogging it down. My suspicion (again without time to really try to understand your query) is that at some point the mixing of tasks is translating into a many-to-many relationship where you have an intermediate result that is a cross product of rows between some of the tables in your query.

oracle pl/sql: datepart () function for weekend exclusion

can i use to_number(to_char()) function in order to exclude all the weekends from a range of dates?
For instance, there are two date columns in my table such as start and finish (in the form of '06/06/2011 10:00:00 am'), and i want to estimate the duration of finish-start excluding Saturdays and Sundays.
If I understand you right you want to calculate the difference between two dates, but exclude the 2 days of each weekend in the range from the result. Is that correct?
If this is what you want the below code should work with the following assumptions:
I am assume start and end will not be on weekends.
I am not validating that end is before start.
Basically its just a matter of working out how many weekends are in the date range. So obviously there's one weekend per 7 days. Then we just have to check if the range wraps around a weekend, and if so add one more.
FUNCION dateDiff( dt_start DATE, dt_end DATE ) RETURN NUMBER
IS
raw_diff NUMBER;
weekends NUMBER;
BEGIN
raw_diff := dt_end - dt_start;
weekends := TRUNC( raw_diff / 7 );
IF( ( dt_start - TRUNC( dt_start, 'DAY' ) )
> ( dt_end - TRUNC( dt_end , 'DAY' ) ) )
THEN
weekends := weekends + 1;
END IF;
RETURN raw_diff - ( weekends * 2 );
END;

Resources