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;