v La modernisation chinoise favorise un nouveau mod�le de d�veloppement humain By chine.in Published On :: 2024-11-13T16:16:01+01:00 Un rapport conjoint intitul� "Un nouveau mod�le pour le progr�s humain et son importance mondiale" a �t� publi� lors du Forum des m�dias et des groupes de r�flexion du Sud global qui s'est tenu lundi � Sao Paulo, au Br�sil. R�dig� par des groupes... Full Article Chine
v Airbus pr�voit une forte demande d'avions en Chine au cours des 20 prochaines ann�es By chine.in Published On :: 2024-11-13T16:40:29+01:00 Airbus a pr�vu que la Chine aurait besoin de plus de 9.500 nouveaux avions de transport de passagers et d'avions cargos au cours des deux prochaines d�cennies, en raison de la forte croissance de la demande de transport a�rien et de fret. Selon... Full Article Chine
v Chine : la partie continentale encourage les �changes entre les jeunes et appelle � lever les restrictions sur les voyages entre les deux rives du d�troit de Taiwan By chine.in Published On :: 2024-11-13T17:45:15+01:00 La partie continentale de la Chine a r�affirm� son engagement � promouvoir les �changes entre les jeunes � travers le d�troit de Taiwan et a demand� aux autorit�s du Parti d�mocrate progressiste (PDP) de lever les restrictions sur les voyages �... Full Article Chine
v Chine : la partie continentale d�clare que les consultations entre les deux rives du d�troit sont possibles en reconnaissant le Consensus de 1992 By chine.in Published On :: 2024-11-13T17:59:59+01:00 Les consultations entre l'Association pour les relations entre les deux rives du d�troit de Taiwan (ARATS) et la Fondation pour les �changes entre les deux rives du d�troit de Taiwan (SEF) pourraient reprendre si les autorit�s de Taiwan... Full Article Chine
v Dix milliards de yuans de commande pour les moteurs a�ronautiques civils chinois By chine.in Published On :: 2024-11-13T18:47:10+01:00 Aero Engine Corporation of China a annonc� mercredi qu'elle avait sign� des bons de commande et des contrats de coop�ration portant sur plus de 1.500 moteurs, pour une valeur totale de plus de 10 milliards de yuans (environ 1,39 milliard de... Full Article Chine
v Chine : la puissance de l'aviation et de la d�fense de la partie continentale est une protection solide pour les compatriotes taiwanais By chine.in Published On :: 2024-11-13T19:06:49+01:00 Une porte-parole de la partie continentale de la Chine a qualifi� les r�sultats et la puissance de la partie continentale dans les domaines de l'aviation, de l'a�rospatiale et de la d�fense nationale de protection "solide et immense" pour les... Full Article China
v Les �changes culturels entre les deux rives du d�troit se poursuivent malgr� les obstacles politiques By chine.in Published On :: 2024-11-13T19:24:29+01:00 Une porte-parole de la partie continentale de la Chine a condamn� mercredi les politiciens du Parti d�mocrate progressiste (PDP) dans la r�gion de Taiwan, qui tentent de faire obstacle aux �changes normaux entre les deux rives du d�troit de Taiwan... Full Article Chine
v Chine : croissance vigoureuse du secteur de la livraison express en octobre By chine.in Published On :: 2024-11-13T20:14:44+01:00 Le secteur chinois de la livraison express a enregistr� une expansion rapide en octobre, avec une acc�l�ration significative du taux de croissance des affaires, selon un indice de l'industrie publi� mercredi par le Bureau national des postes. ... Full Article livraison express
v Une porte-parole de la partie continentale condamne les autorit�s du PDP pour avoir "ruin� Taiwan" By chine.in Published On :: 2024-11-13T20:35:09+01:00 Une porte-parole de la partie continentale de la Chine a vivement critiqu� mercredi les autorit�s du Parti d�mocrate progressiste (PDP) de Taiwan pour avoir cherch� � obtenir le soutien des Etats-Unis, d�clarant que plus leur d�pendance � l'�gard... Full Article Chine
v Chine : les investissements ferroviaires en hausse de 10,9% au cours des dix premiers mois By chine.in Published On :: 2024-11-13T20:47:04+01:00 La Chine a continu� � accro�tre ses investissements dans la construction ferroviaire depuis le d�but de cette ann�e, d'apr�s des donn�es publi�es mercredi par l'op�rateur ferroviaire du pays. Durant la p�riode janvier-octobre, les investissements... Full Article Chine
v La Chine et le Vietnam conviennent de renforcer leur coop�ration en mati�re de s�curit� By chine.in Published On :: 2024-11-13T21:29:50+01:00 Chen Wenqing, haut responsable du Parti communiste chinois (PCC), a rencontr� Phan Dinh Trac, membre du Bureau politique et pr�sident de la Commission des affaires int�rieures du Comit� central du Parti communiste vietnamien (PCV), mardi � Beijing. ... Full Article Chine
v La Chine est pr�te � cr�er davantage d'opportunit�s pour les partenaires de l'Asie-Pacifique gr�ce au d�veloppement et � l'ouverture By chine.in Published On :: 2024-11-13T21:43:31+01:00 La Chine est pr�te � profiter de la 31e r�union des dirigeants �conomiques de l'APEC pour cr�er davantage d'opportunit�s pour les partenaires de l'Asie-Pacifique avec un d�veloppement de haute qualit� et une ouverture de haut niveau, a d�clar�... Full Article Chine
v Le commerce de la Chine avec les autres �conomies de l'APEC a atteint un niveau record entre janvier et octobre By chine.in Published On :: 2024-11-13T21:47:46+01:00 Le commerce de la Chine avec les autres �conomies de l'APEC a atteint un niveau record de 21.270 milliards de yuans (environ 2.950 milliards de dollars) au cours des dix premiers mois de 2024, selon les donn�es publi�es mercredi par l'Administration... Full Article APEC
v Implementing NSLookup In Java By www.ensode.net Published On :: NSLookup is a command line utility that, given an IP address, returns the corresponding host name and vice versa. This article explains how to write an NSLookup clone in Java. Full Article
v Introduction To Maven 2 By www.ensode.net Published On :: Maven is a tool used to build Java code, similar to ANT. However Maven has a number of advantages over ANT, the main one being it being able to automatically download a project's dependencies from a central repository. Full Article
v Guide To Installing Fedora Core 6 On HP Pavilion dv2000 Series Laptops By www.ensode.net Published On :: This guide provides installation and configuration instructions for installing Fedora Core 6 on HP Pavilion dv2000 series laptops. Full Article
v Developing Rich EJB ClientsWith GlassFish By www.ensode.net Published On :: GlassFish provides features to make it easy to develop stand alone, Java Swing based EJB clients. In this article we explain how to take advantage of these features. Full Article
v A Java Developer's Review of Fedora 8 By www.ensode.net Published On :: The latest version of the Fedora Linux Distribution includes a completely open source Java compiler and JVM called IcedTea, in addition to several Java tools and libraries. We took Fedora 8's tools for a spin and reported our findings in this article. Full Article
v Adding "Maven-Like" Dependency Management To NetBeans Projects with Ivy By www.ensode.net Published On :: When working with Maven projects from NetBeans, some very nice NetBeans features are lost, such as the ability to use the Matisse GUI Builder, developing JSF web applications visually and automatically generating JPA entities from existing database schemas. In this article we explain how to keep all the benefits of Maven without losing NetBeans functionality by integrating Ivy into NetBeans projeccts. Full Article
v PSV gaat later dit seizoen een eigen gamer inzetten By voetbal.blog.nl Published On :: Wed, 10 Aug 2016 17:46:09 +0000 Huh?! PSV speelt volgens het Eindhovens Dagblad in op de onder jongeren razend populaire markt voor computergames. De club trekt ...... Lees verder: PSV gaat later dit seizoen een eigen gamer inzetten Full Article .Algemeen Nederland Opinie PSV gamen gamer games philips psvers toernooi
v Grinnik, foutje bedankt… (The Sun noemt krant oud-aanvoerder van Ajax) By voetbal.blog.nl Published On :: Wed, 10 Aug 2016 21:35:47 +0000 ... Lees verder: Grinnik, foutje bedankt… (The Sun noemt krant oud-aanvoerder van Ajax) Full Article Ajax Buitenland sun
v Nieuwe tegenslag voor degradant Aston Villa: nu al uit de beker geknikkerd By voetbal.blog.nl Published On :: Thu, 11 Aug 2016 05:39:25 +0000 Ik denk dat we voorzichtig kunnen stellen dat 2016 niet het jaar is van Aston Villa... De club in de ...... Lees verder: Nieuwe tegenslag voor degradant Aston Villa: nu al uit de beker geknikkerd Full Article Buitenland aston villa beker competitie degradant engeland luton verlies
v ‘Traoré op huurbasis van Chelsea naar Ajax’ By voetbal.blog.nl Published On :: Thu, 11 Aug 2016 08:14:46 +0000 Het ging er gisteren al over en het lijkt er sterk op dat het vandaag rond gaat komen: Bertrand Traoré ...... Lees verder: ‘Traoré op huurbasis van Chelsea naar Ajax’ Full Article Ajax trainers Transfernieuws vitesse bosz chelsea cl huurbasis transfer traore
v Het is niet best gesteld met de conditie van de Nederlandse scheidsrechters By voetbal.blog.nl Published On :: Thu, 11 Aug 2016 08:19:19 +0000 Er wordt gezegd dat het niet te maken heeft met overgewicht na de zomerstop, maar mogelijk is het toch een ...... Lees verder: Het is niet best gesteld met de conditie van de Nederlandse scheidsrechters Full Article blessurenieuws Jupiler League Nederland Opinie conditite jupiler league nederlandse scheidsrechters test
v Voetbal op de Olympische Spelen: Duitsland – Fiji: 10 – 0 By voetbal.blog.nl Published On :: Thu, 11 Aug 2016 09:20:25 +0000 "Tsja... als die eerste goal aan de andere kant valt, krijg je een hele andere wedstrijd..." Een voetbal-cliché (smoes) voor een ...... Lees verder: Voetbal op de Olympische Spelen: Duitsland – Fiji: 10 – 0 Full Article Buitenland duitsland fiji olympische spelen voetbal
v Support je vereniging met een nieuw spandoek By voetbal.blog.nl Published On :: Tue, 16 Aug 2016 10:16:31 +0000 Je hebt de perfecte supporterslook aan en kent alle clubliederen uit je hoofd, maar toch ontbreekt het nog aan iets. ...... Lees verder: Support je vereniging met een nieuw spandoek Full Article .Algemeen
v Maak live een zinderende Premier League wedstrijd mee! By voetbal.blog.nl Published On :: Mon, 23 Jan 2017 10:20:12 +0000 Het voetbalseizoen 2016/2017 is alweer in volle gang en de twee hoogste leagues in Engeland, de Premier League & Championship, ...... Lees verder: Maak live een zinderende Premier League wedstrijd mee! Full Article .Algemeen
v Nieuw voetbalgear nodig? By voetbal.blog.nl Published On :: Fri, 14 Apr 2017 06:41:49 +0000 Voetbal: het is een sport waar we ons allemaal een beetje mee verbonden voelen en de sport heeft dan ook ...... Lees verder: Nieuw voetbalgear nodig? Full Article .Algemeen
v It's Official - Blog Bloke has moved By www.blog-bloke.com Published On :: Fri, 4 Jan 2008 13:01:00 -0800 Hi Blokesters. It's official now and InstaBloke has moved over to Blog Bloke dot com, so please make a note of it and update your bookmarks as well as the newsfeed. You should also check out my latest post explaining all of the gory details. It's a doozy.See you there! Full Article
v In welke provincie wonen de beste fietsers? By wielrennen.blog.nl Published On :: Thu, 01 Jun 2017 17:37:42 +0000 De Nederlandse man rijdt gemiddeld 50,9 kilometer per keer als hij op zijn racefiets klimt. De Zeeuwen fietsen het snelst ...... Lees verder: In welke provincie wonen de beste fietsers? Full Article Algemeen
v Trekz Titanium maakt fietsen met muziek veilig By wielrennen.blog.nl Published On :: Fri, 21 Jul 2017 08:31:56 +0000 Veilig muziek luisteren op de fiets Het is een goedbewaard geheim dat wij ook met ons kaakbeen geluiden opvangen. De Aftershokz ...... Lees verder: Trekz Titanium maakt fietsen met muziek veilig Full Article Algemeen
v Caja Rural en de ploegentijdrit in de Vuelta: Een kijkje achter de schermen By wielrennen.blog.nl Published On :: Fri, 01 Sep 2017 17:15:54 +0000 Een kijkje achter de schermen bij Caja Rural, voorafgaand aan de ploegentijdrit tijdens de Vuelta-start in Nîmes. ... Lees verder: Caja Rural en de ploegentijdrit in de Vuelta: Een kijkje achter de schermen Full Article Algemeen Caja Rural ploegentijdrit Vuelta Vuelta 2017
v ALO Drinks: Heerlijk voor na het wielrennen By wielrennen.blog.nl Published On :: Thu, 05 Oct 2017 14:06:04 +0000 De naam Aloë Vera zal vooral bekend in de oren klinken van de zalf. Deze zalf is gemaakt van de ...... Lees verder: ALO Drinks: Heerlijk voor na het wielrennen Full Article Algemeen ALO Drink Alo Vera Aloë Vera
v Zwift levert renner profcontract op By wielrennen.blog.nl Published On :: Wed, 22 Nov 2017 16:07:29 +0000 De eerste wielrenner die via het fietsprogramma Zwift een profcontract heeft verdiend is een feit. Team Dimension Data schreef eerder ...... Lees verder: Zwift levert renner profcontract op Full Article Algemeen Ollie Jones profcontract Zwift
v Bitemojo self-guided foodtours: een review By wielrennen.blog.nl Published On :: Mon, 26 Feb 2018 17:47:19 +0000 BARCELONA – Het is goed uitkijken in het drukke Barcelona. Bitemojo heeft wielrennen.blog.nl een self-guided food tour aangeboden die wij ...... Lees verder: Bitemojo self-guided foodtours: een review Full Article Algemeen Bitemojo
v EBSQ Art of the Day - July 19, 2018: Vincent and Sunflowers by Tracey Allyn Greene By www.ebsqart.com Published On :: Thu, 19 Jul 2018 00:00:01 GMT EBSQ Art of the Day July 19, 2018 Vincent and Sunflowers © by: Tracey Allyn Greene View today's art on EBSQ Search for EBSQ: eBay ImageKind Etsy ArtByUs.com Full Article
v EBSQ Art of the Day - July 22, 2018: Sunflowers by Shane Darren Ervin By www.ebsqart.com Published On :: Sun, 22 Jul 2018 00:00:01 GMT EBSQ Art of the Day July 22, 2018 Sunflowers © by: Shane Darren Ervin View today's art on EBSQ Search for EBSQ: eBay ImageKind Etsy ArtByUs.com Full Article
v EBSQ Art of the Day - July 23, 2018: Sunflower Ladybug Vignette by Pamela K Wilhelm By www.ebsqart.com Published On :: Mon, 23 Jul 2018 00:00:01 GMT EBSQ Art of the Day July 23, 2018 Sunflower Ladybug Vignette © by: Pamela K Wilhelm View today's art on EBSQ Search for EBSQ: eBay ImageKind Etsy ArtByUs.com Full Article
v RFE - source code now available By www.wehlou.com Published On :: Sun, 4 Apr 2004 15:10:46 +0200 On request, I've posted the source code to the RSS Feed Editor. Full Article
v 12C: IN DATABASE ARCHIVING By www.orafaq.com Published On :: Sun, 28 Jul 2013 08:42:59 +0000 articles: Technical ArticlesIn this post, I will demonstrate a new feature introduced in 12c : In database archiving. It enables you to archive rows within a table by marking them as invisible. This is accomplshed by means of a hidden column ORA_ARCHIVE_STATE. These invisible rows are not visible to the queries but if needed, can be viewed , by setting a session parameter ROW ARCHIVAL VISIBILITY. Overview: -- Create test user uilm, tablespace ilmtbs -- Connect as user uilm -- create and populate test table (5 rows) ilmtab with row archival clause -- Note that the table has an additional column ORA_ARCHIVE_STATE automatically created and has the default value of 0 (indicates that row is active) -- Note that this column is not visible when we describe the table or simply issue select * from ... -- We need to access data dictionary to view the column -- Make two rows in the table inactive by setting ORA_ARCHIVE_STATE column to a non zero value. -- Check that inactive rows are not visible to query -- Set the parameter ROW ARCHIVAL VISIBILITY = all to see inactive rows also -- Set the parameter ROW ARCHIVAL VISIBILITY = active to hide inactive rows -- Issue an insert into ... select * and check that only 3 visible rows are inserted -- Set the parameter ROW ARCHIVAL VISIBILITY = all to see inactive rows also -- Issue an insert into ... select * and check that all the rows are inserted but ORA_ARCHIVE_STATE is not propagated in inserted rows -- Disable row archiving in the table and check that column ORA_ARCHIVE_STATE is automatically dropped -- drop tablespace ilmtbs and user uilm Implementation : -- Create test user, tablespace and test table SQL> conn sys/oracle@em12c:1523/pdb1 as sysdba sho con_name CON_NAME ------------------------------ PDB1 SQL> set sqlprompt PDB1> PDB1>create tablespace ilmtbs datafile '/u02/app/oracle/oradata/cdb1/pdb1/ilmtbs01.dbf' size 1m; grant connect, resource, dba to uilm identified by oracle; alter user uilm default tablespace ilmtbs; conn uilm/oracle@em12c:1523/pdb1 sho con_name CON_NAME ------------------------------ PDB1-- create table with "row archival clause" PDB1>drop table ilmtab purge; create table ilmtab (id number, txt char(15)) row archival; insert into ilmtab values (1, 'one'); insert into ilmtab values (2, 'two'); insert into ilmtab values (3, 'three'); insert into ilmtab values (4, 'four'); insert into ilmtab values (5, 'five'); commit;-- Note that the table has an additional column ORA_ARCHIVE_STATE automatically created and has the default value of 0 (indicates that row is active) PDB1>col ora_archive_state for a20 select id, txt, ora_archive_state from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 1 one 0 2 two 0 3 three 0 4 four 0 5 five 0-- Note that this column is not visible when we describe the table or simply issue select * from ... PDB1>desc ilmtab Name Null? Type ----------------------------------------- -------- ---------------------------- ID NUMBER TXT CHAR(15) PDB1>select * from ilmtab; ID TXT ---------- --------------- 1 one 2 two 3 three 4 four 5 five -- Since the column is invisible, let me try and make it visible-- Note that Since the column is maintained by oracle itself, user can't modify its attributes PDB1>alter table ilmtab modify (ora_archive_state visible); alter table ilmtab modify (ora_archive_state visible) *ERROR at line 1:ORA-38398: DDL not allowed on the system ILM column -- We need to access data dictionary to view the column-- Note that this column is shown as hidden and has not been generated by user PDB1>col hidden for a7 col USER_GENERATED for 20 col USER_GENERATED for a20 select TABLE_NAME, COLUMN_NAME, HIDDEN_COLUMN, USER_GENERATED from user_tab_cols where table_name='ILMTAB'; TABLE_NAME COLUMN_NAME HID USER_GENERATED ----------- -------------------- --- -------------------- ILMTAB ORA_ARCHIVE_STATE YES NO ILMTAB ID NO YES ILMTAB TXT NO YES-- We can make selected rows in the table inactive by setting ORA_ARCHIVE_STATE column to a non zero value. This can be accomplished using update table... set ORA_ACRHIVE_STATE = . <non-zero value> . dbms_ilm.archivestatename(1) -- Let's update row with id =1 with ORA_ARCHIVE_STATE=2 and update row with id =2 with dbms_ilm.archivestatename(2) PDB1>update ilmtab set ora_archive_state=2 where id=1; update ilmtab set ora_archive_state= dbms_ilm.archivestatename(2) where id=2;-- Let's check whether updates have been successful and hidden rows are not visible PDB1>select id, txt, ORA_ARCHIVE_STATE from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 3 three 0 4 four 0 5 five 0 -- The updated rows are not visible!! -- Quite logical since we have made the rows active and by default only active rows are visible -- To see inactive rows also, we need to set the parameter ROW ARCHIVAL VISIBILITY = all at session level -- Note that the column ORA_ARCHIVE_STATE has been set to 1 for id =2 although we had set it to 2 using dbms_ilm.archivestatename(2) PDB1>alter session set ROW ARCHIVAL VISIBILITY = all; select id, txt, ORA_ARCHIVE_STATE from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 1 one 2 2 two 1 3 three 0 4 four 0 5 five 0-- Note that the column ORA_ARCHIVE_STATE has been set to 1 for id =2 although we had set it to 2 using dbms_ilm.archivestatename(2) -- Let's find out why-- Note that The function dbms_ilm.archivestatename(n) returns only two values 0 for n=0 and 1 for n <> 0 PDB1>col state0 for a8 col state1 for a8 col state2 for a8 col state3 for a8 select dbms_ilm.archivestatename(0) state0 ,dbms_ilm.archivestatename(1) state1, dbms_ilm.archivestatename(2) state2,dbms_ilm.archivestatename(3) state3 from dual; STATE0 STATE1 STATE2 STATE3 -------- -------- -------- -------- 0 1 1 1-- In order to make the inactive rows (id=1,2) hidden again, we need to set the parameter ROW ARCHIVAL VISIBILITY = Active PDB1>alter session set row archival visibility = active; select id, txt, ORA_ARCHIVE_STATE from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 3 three 0 4 four 0 5 five 0-- Let's issue an insert into ... select * -- Note that only 3 new rows are visible PDB1>insert into ilmtab select * from ilmtab; select id, txt, ora_archive_state from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 3 three 0 4 four 0 5 five 0 3 three 0 4 four 0 5 five 0 6 rows selected. -- I want to check if hidden rows were also inserted -- Let's check by making hidden rows visible again-- Note that only visible rows(id=3,4,5) were inserted PDB1>alter session set row archival visibility=all; select id, txt, ora_archive_state from ilmtab; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 1 one 2 2 two 1 3 three 0 4 four 0 5 five 0 3 three 0 4 four 0 5 five 0 8 rows selected.-- Let's set row archival visibility = all and then again insert rows from ilmtab-- Note that all the 8 rows are inserted but ORA_ARCHIVE_STATE ha not been copied ORA_ARCHIVE_STATE <> 0 in only 2 records (id = 1,2) even now. PDB1>alter session set row archival visibility=all; insert into ilmtab select * from ilmtab; select id, txt, ora_archive_state from ilmtab order by id; ID TXT ORA_ARCHIVE_STATE ---------- --------------- -------------------- 1 one 0 1 one 2 2 two 0 2 two 1 3 three 0 3 three 0 3 three 0 3 three 0 4 four 0 4 four 0 4 four 0 4 four 0 5 five 0 5 five 0 5 five 0 5 five 0 16 rows selected.-- Disable row level archiving for the table -- Note that as soon as row archiving is disabled, pseudo column ora_archive_state is dropped automatically PDB1>alter table ilmtab no row archival; select id, txt, ORA_ARCHIVE_STATE from ilmtab; ERROR at line 1:ORA-00904: "ORA_ARCHIVE_STATE": invalid identifier PDB1>col hidden for a7 col USER_GENERATED for 20 col USER_GENERATED for a20 select TABLE_NAME, COLUMN_NAME, HIDDEN_COLUMN, USER_GENERATED from user_tab_cols where table_name='ILMTAB'; TABLE_NAME COLUMN_NAME HID USER_GENERATED ----------- -------------------- --- -------------------- ILMTAB ID NO YES ILMTAB TXT NO YESNote : Had we created this table using sys, we could not have disabled row archiving . -- cleanup -- PDB1>conn sys/oracle@em12c:1523/pdb1 as sysdba drop tablespace ilmtbs including contents and datafiles; drop user uilm cascade;References: http://docs.oracle.com/cd/E16655_01/server.121/e17613/part_lifecycle.htm#VLDBG14154 ---------------------------------------------------------------------------------------------------- Oracle 12c Index ---------------------------------------------------------------------------------------------- Full Article
v Inverted tables: an alternative to relational structures By www.orafaq.com Published On :: Sun, 08 Sep 2013 08:52:30 +0000 articles: WarehousingThe inverted table format can deliver fast and flexible query capabilities, but is not widely used. ADABAS is probably the most successful implementation, but how often do you see that nowadays? Following is a description of how to implement inverted structures within a relational database. All code run on Oracle Database 12c, release 12.1.0.1. Consider this table and a few rows, that describe the contents of my larder: create table food(id number,capacity varchar2(10),container varchar2(10),item varchar2(10)); insert into food values(1,'large','bag','potatoes'); insert into food values(2,'small','box','carrots'); insert into food values(3,'medium','tin','peas'); insert into food values(4,'large','box','potatoes'); insert into food values(5,'small','tin','carrots'); insert into food values(6,'medium','bag','peas'); insert into food values(7,'large','tin','potatoes'); insert into food values(8,'small','bag','carrots'); insert into food values(9,'medium','box','peas'); The queries I run against the table might be "how many large boxes have I?" or "give me all the potatoes, I don't care about how they are packed". The idea is that I do not know in advance what columns I will be using in my predicate: it could be any combination. This is a common issue in a data warehouse. So how do I index the table to satisfy any possible query? Two obvious possibilities: First, build an index on each column, and the optimizer can perform an index_combine operation on whatever columns happen to be listed in the predicate. But that means indexing every column - and the table might have hundreds of columns. No way can I do that. Second, build a concatenated index across all the columns: in effect, use an IOT. That will give me range scan access if any of the predicated columns are in the leading edge of the index key followed by filtering on the rest of the predicate. Or if the predicate does not include the leading column(s), I can get skip scan access and filter. But this is pretty useless, too: there will be wildly divergent performance depending on the predicate. The answer is to invert the table: create table inverted(colname varchar2(10),colvalue varchar2(10),id number); insert into inverted select 'capacity',capacity,id from food; insert into inverted select 'container',container,id from food; insert into inverted select 'item',item,id from food; Now just one index on each table can satisfy all queries: create index food_i on food(id); create index inverted_i on inverted(colname,colvalue); To retrieve all the large boxes: orclz> set autotrace on explain orclz> select * from food where id in 2 (select id from inverted where colname='capacity' and colvalue='large' 3 intersect 4 select id from inverted where colname='container' and colvalue='box'); ID CAPACITY CONTAINER ITEM ---------- ---------- ---------- ---------- 4 large box potatoes Execution Plan ---------------------------------------------------------- Plan hash value: 1945359172 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | C --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | 141 | | 1 | MERGE JOIN | | 3 | 141 | | 2 | TABLE ACCESS BY INDEX ROWID | FOOD | 9 | 306 | | 3 | INDEX FULL SCAN | FOOD_I | 9 | | |* 4 | SORT JOIN | | 3 | 39 | | 5 | VIEW | VW_NSO_1 | 3 | 39 | | 6 | INTERSECTION | | | | | 7 | SORT UNIQUE | | 3 | 81 | | 8 | TABLE ACCESS BY INDEX ROWID BATCHED| INVERTED | 3 | 81 | |* 9 | INDEX RANGE SCAN | INVERTED_I | 3 | | | 10 | SORT UNIQUE | | 3 | 81 | | 11 | TABLE ACCESS BY INDEX ROWID BATCHED| INVERTED | 3 | 81 | |* 12 | INDEX RANGE SCAN | INVERTED_I | 3 | | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("ID"="ID") filter("ID"="ID") 9 - access("COLNAME"='capacity' AND "COLVALUE"='large') 12 - access("COLNAME"='container' AND "COLVALUE"='box') Note ----- - dynamic statistics used: dynamic sampling (level=2) orclz> Or all the potatoes: orclz> select * from food where id in 2 (select id from inverted where colname='item' and colvalue='potatoes'); ID CAPACITY CONTAINER ITEM ---------- ---------- ---------- ---------- 1 large bag potatoes 4 large box potatoes 7 large tin potatoes Execution Plan ---------------------------------------------------------- Plan hash value: 762525239 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cos --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 3 | 183 | | 1 | NESTED LOOPS | | | | | 2 | NESTED LOOPS | | 3 | 183 | | 3 | SORT UNIQUE | | 3 | 81 | | 4 | TABLE ACCESS BY INDEX ROWID BATCHED| INVERTED | 3 | 81 | |* 5 | INDEX RANGE SCAN | INVERTED_I | 3 | | |* 6 | INDEX RANGE SCAN | FOOD_I | 1 | | | 7 | TABLE ACCESS BY INDEX ROWID | FOOD | 1 | 34 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("COLNAME"='item' AND "COLVALUE"='potatoes') 6 - access("ID"="ID") Note ----- - dynamic statistics used: dynamic sampling (level=2) - this is an adaptive plan orclz> Of course, consideration needs to be given to handling more complex boolean expressions; maintaining the inversion is going to take resources; and a query generator has to construct the inversion code and re-write the queries. But In principle, this structure can deliver indexed access for unpredictable predicates of any number of any columns, with no separate filtering operation. Can you do that with a normalized star schema? I don't think so. I hope this little thought experiment has stimulated the little grey cells, and made the point that relational structures are not always optimal for all problems. -- John Watson Oracle Certified Master DBA http://skillbuilders.com Full Article
v Recursion with recursive WITH By www.orafaq.com Published On :: Tue, 24 May 2016 09:03:09 +0000 articles: SQL & PL/SQLI recently had the opportunity to talk with Tom Kyte (!), and in the course of our conversation, he really made me face up to the fact that the SQL syntax I use every day is frozen in time: I’m not making much use of the analytic functions and other syntax that Oracle has introduced since 8i. Here’s a brief history of these additions to Oracle SQL, from Keith Laker, Oracle’s Product Manager for Analytical SQL: 8i Window functions 9i Rollup, grouping sets, cube, enhanced window functions 10g SQL Model clause, statistical functions, partition outer join 11g SQL Pivot clause, Recursive WITH, Listagg, Nth value 12c Pattern matching, Top N Not only do these make complex queries much, much simpler and easier, they are also much faster for the same result than non-analytic SQL, as Tom Kyte has shown repeatedly on his blog and in his books. So, I was sold and I wanted to jump in with Recursive WITH. The WITH clause lets you define inline views to use across an entire query, and the coolest thing about this is that you can define the subquery recursively – so that the inline view calls itself. Recursive WITH basic syntax: WITH Tablename (col1, col2, ...) AS (SELECT A, B, C... FROM dual --anchor member UNION ALL SELECT A', B', C'... from Tablename where... --recursive member ) select ... from Tablename where ... Refactoring the Factorial One fun thing about recursive WITH, aka recursive subquery refactoring, is the ease with which we can implement a recursive algorithm in SQL. Let’s warm up with a classic example of recursion: finding the factorial of a number. Factorial(n) = n! = 1*2*3*…*n . It’s a classic example because Factorial(n) can be defined recursively as: Factorial(0) = 1 Factorial(n) = Factorial(n-1) * n Here’s a first pass at implementing that directly in SQL to find the factorial of 5, using a recursive WITH subquery: WITH Factorial (operand,total_so_far) AS (SELECT 5 operand, 5 total_so_far FROM dual -- Using anchor member to pass in "5" UNION ALL SELECT operand-1, total_so_far * (operand-1) FROM Factorial WHERE operand > 1) SELECT * FROM Factorial; OPERAND TOTAL_SO_F ---------- ---------- 5 5 4 20 3 60 2 120 1 120 and to display just the result, we select it from Factorial: WITH Factorial (operand,total_so_far) AS (SELECT 5 operand, 5 total_so_far FROM dual -- Find the factorial of 5 UNION ALL SELECT operand-1, total_so_far * (operand-1) FROM Factorial WHERE operand > 1) SELECT MAX(operand) || '! = ' || MAX(total_so_far) AS RESULT FROM Factorial; RESULT ----------------- 5! = 120 Ahem! I have cheated a little for simplicity here. The query doesn’t take into account that Factorial(0) = 1: WITH Factorial (operand,total_so_far) AS (SELECT 0 operand, 0 total_so_far FROM dual -- Find the factorial of 0 UNION ALL SELECT operand-1, total_so_far * (operand-1) FROM Factorial WHERE operand > 1) -- This is going to get me nowhere fast... SELECT * FROM Factorial; OPERAND TOTAL_SO_F ---------- ---------- 0 0 To do it properly, we need to include Factorial(0) = 1 in the recursive subquery: WITH Factorial (operand,total_so_far) AS (SELECT 0 operand, 0 total_so_far FROM dual -- Find the factorial of 0 UNION ALL SELECT operand-1, CASE -- Factorial (0) = 1 WHEN operand=0 THEN 1 ELSE (total_so_far * (operand-1)) END FROM Factorial WHERE operand >= 0) SELECT MAX(operand) || '! = ' || MAX(total_so_far) AS RESULT FROM Factorial; RESULT ------------------------------------------------------------------------------------ 0! = 1 We can also reverse direction and recursively build a table of factorials, multiplying as we go. That’s the approach Lucas Jellema takes in his excellent blog post on factorials in SQL. WITH Factorial (operand,output) AS (SELECT 0 operand, 1 output FROM dual UNION ALL SELECT operand+1, output * (operand+1) FROM Factorial WHERE operand < 5) SELECT * FROM Factorial; OPERAND OUTPUT ---------- ---------- 0 1 1 1 2 2 3 6 4 24 5 120 There are two nice things about this approach: first, every row of the subquery result contains n and n! , and second, the rule that 0! = 1 is elegantly captured in the anchor member. denrael ev’ew tahw gniylppA Now let’s do something more interesting – reversing a string. Here’s some sample code in C from the CS 211 course at Cornell: public String reverseString(String word) { if(word == null || word.equals("")) return word; else return reverseString(word.substring(1, word.length())) + word.substring(0,1); } Let’s run through an example word to see how it works. For simplicity I’ll write reverseString(“word”) as r(word). Using “cat” as the word, stepping through the algorithm gives: r(cat) = r(r(at))+c = r(r(r(t))+a+c = r(r(r(r())+t+a+c = ''+t+a+c = tac Now to rewrite the same function in SQL. Using the same example string, “cat,” I want my recursively defined table to look like this: in out -------- cat at c t ac tac In C, the initial letter in the word is the 0th letter, and in SQL, it’s the 1st letter. So the C expression word.substring(1,N) corresponds to SQL expression substr(word,2,N-1) . With that in mind, it’s easy to rewrite the C algorithm in SQL: WITH WordReverse (INPUT, output) AS (SELECT 'CAT' INPUT, NULL output FROM dual UNION ALL SELECT substr(INPUT,2,LENGTH(INPUT)-1), substr(INPUT,1,1) || output FROM wordReverse WHERE LENGTH(INPUT) > 0 ) SELECT * FROM wordReverse; INPUT OUTP -------- ---- CAT AT C T AC TAC NOTE: if using 11.2.0.3 or earlier, you might get “ORA-01489: result of string concatenation is too long” when reversing anything longer than a few letters. This is due to Bug 13876895: False ora-01489 on recursive WITH clause when concatenating columns. The bug is fixed in 11.2.0.4 and 12.1.0.1, and there’s an easy workaround: Cast one of the inputs to the concatenation as a varchar2(4000). We could make this query user-friendlier by using a sql*plus variable to hold the input string. Another approach is to add an additional subquery to the with block to “pass in” parameters. I picked this up from Lucas Jellema’s post mentioned above, and wanted to give it a try, so I’ll add it in to my WordReverse query here. Let’s use this to reverse a word that’s really quite atrocious: WITH params AS (SELECT 'supercalifragilisticexpialidocious' phrase FROM dual), WordReverse (inpt, outpt) AS (SELECT phrase inpt, CAST(NULL AS varchar2(4000)) outpt FROM params UNION ALL SELECT substr(inpt,2,LENGTH(inpt)-1), substr(inpt,1,1) || outpt FROM wordReverse WHERE LENGTH(inpt) > 0 ) SELECT phrase,outpt AS reversed FROM wordReverse, params WHERE LENGTH(outpt) = LENGTH(phrase) ; PHRASE REVERSED ---------------------------------- ---------------------------------------- supercalifragilisticexpialidocious suoicodilaipxecitsiligarfilacrepus Now you might not have needed to know how to spell “supercalifragilisticexpialidocious” backwards, but one recursive requirement that does come up often is querying hierarchical data. I wrote a series of posts on hierarchical data recently, using Oracle’s CONNECT BY syntax. But recursive WITH can also be used to query hierarchical data. That’ll be the subject of my next post. Republished with permission. Original URL: http://rdbms-insight.com/wp/?p=94 Full Article
v Recursive WITH, part II: Hierarchical queries By www.orafaq.com Published On :: Fri, 03 Jun 2016 09:38:25 +0000 articles: SQL & PL/SQLIn my last post, I looked at using recursive WITH to implement simple recursive algorithms in SQL. One very common use of recursion is to traverse hierarchical data. I recently wrote a series of posts on hierarchical data, using Oracle’s CONNECT BY syntax and a fun example. In this post, I’ll be revisiting the same data using recursive WITH. There are dozens of examples of hierarchical data, from the EMP table to the Windows Registry to binary trees, but I went with something more fun: the skeleton from the old song “Dem Dry Bones”. Quote:Toe bone connected to the foot bone Foot bone connected to the heel bone Heel bone connected to the ankle bone Ankle bone connected to the shin bone Shin bone connected to the knee bone Knee bone connected to the thigh bone Thigh bone connected to the hip bone Hip bone connected to the back bone Back bone connected to the shoulder bone Shoulder bone connected to the neck bone Neck bone connected to the head bone Since every bone has only one ancestor, and there is a root bone with no ancestor, this is hierarchical data and we can stick it in a table and query it. SELECT * FROM skeleton; BONE CONNECTED_TO_THE ---------------------------------------- ---------------------------------------- shoulder neck back shoulder hip back thigh hip knee thigh leg knee foot heel head neck head toe foot arm shoulder wrist arm ankle leg heel ankle finger wrist a rib back b rib back c rib back You can see that I added some ribs and an arm to make the skeleton more complete! Using Oracle’s CONNECT BY syntax: SQL> col bone FOR a10 SQL> col connected_to_the FOR a9 SQL> col level FOR 99 SQL> col bone_tree FOR a27 SQL> col path FOR a65 SELECT bone, connected_to_the, level, lpad(' ',2*level, ' ') || bone AS bone_tree , ltrim(sys_connect_by_path(bone,'>'),'>') AS path FROM skeleton START WITH connected_to_the IS NULL CONNECT BY prior bone=connected_to_the ORDER siblings BY 1 BONE CONNECTED LEVEL BONE_TREE PATH ---------- --------- ----- --------------------------- ----------------------------------------------------------------- head 1 head head neck head 2 neck head>neck shoulder neck 3 shoulder head>neck>shoulder arm shoulder 4 arm head>neck>shoulder>arm wrist arm 5 wrist head>neck>shoulder>arm>wrist finger wrist 6 finger head>neck>shoulder>arm>wrist>finger back shoulder 4 back head>neck>shoulder>back a rib back 5 a rib head>neck>shoulder>back>a rib b rib back 5 b rib head>neck>shoulder>back>b rib c rib back 5 c rib head>neck>shoulder>back>c rib hip back 5 hip head>neck>shoulder>back>hip thigh hip 6 thigh head>neck>shoulder>back>hip>thigh knee thigh 7 knee head>neck>shoulder>back>hip>thigh>knee leg knee 8 leg head>neck>shoulder>back>hip>thigh>knee>leg ankle leg 9 ankle head>neck>shoulder>back>hip>thigh>knee>leg>ankle heel ankle 10 heel head>neck>shoulder>back>hip>thigh>knee>leg>ankle>heel foot heel 11 foot head>neck>shoulder>back>hip>thigh>knee>leg>ankle>heel>foot toe foot 12 toe head>neck>shoulder>back>hip>thigh>knee>leg>ankle>heel>foot>toe The above CONNECT BY query uses the LEVEL pseudocolumn and the SYS_CONNECT_BY_PATH function. With recursive WITH, there’s no need for these built-ins because these values fall naturally out of the recursion. Let’s start with the basic hierarchical query rewritten in recursive WITH. The hierarchical relationship in our table is: Parent(row.bone) = row.connected_to_the WITH skellarchy (bone, parent) AS ( SELECT bone, connected_to_the FROM skeleton WHERE bone = 'head' -- Start with the root UNION ALL SELECT s.bone, s.connected_to_the FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the -- Parent(row.bone) = row.connected_to_the ) SELECT * FROM skellarchy; BONE PARENT ---------- ---------------------------------------- head neck head shoulder neck back shoulder arm shoulder hip back wrist arm a rib back b rib back c rib back thigh hip finger wrist knee thigh leg knee ankle leg heel ankle foot heel toe foot Because we built up the SKELLARCHY table recursively, it’s easy to make an equivalent to the LEVEL pseudocolumn; it falls right out of the recursion: WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SELECT * FROM skellarchy; BONE PARENT THE_LEVEL ---------- ---------- ---------- head 0 neck head 1 shoulder neck 2 back shoulder 3 arm shoulder 3 hip back 4 wrist arm 4 a rib back 4 b rib back 4 c rib back 4 thigh hip 5 finger wrist 5 knee thigh 6 leg knee 7 ankle leg 8 heel ankle 9 foot heel 10 toe foot 11 and it’s also easy to build up a path from root to the current node like the “SYS_CONNECT_BY_PATH” function does for CONNECT BY queries: WITH skellarchy (bone, parent, the_level, the_path) AS ( SELECT bone, connected_to_the, 0, CAST(bone AS varchar2(4000)) FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1, r.the_path || '->' || s.bone FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SELECT * FROM skellarchy; BONE PARENT THE_LEVEL THE_PATH ---------- ---------- --------- -------------------------------------------------------------------------------- head 0 head neck head 1 head->neck shoulder neck 2 head->neck->shoulder back shoulder 3 head->neck->shoulder->back arm shoulder 3 head->neck->shoulder->arm hip back 4 head->neck->shoulder->back->hip wrist arm 4 head->neck->shoulder->arm->wrist a rib back 4 head->neck->shoulder->back->a rib b rib back 4 head->neck->shoulder->back->b rib c rib back 4 head->neck->shoulder->back->c rib thigh hip 5 head->neck->shoulder->back->hip->thigh finger wrist 5 head->neck->shoulder->arm->wrist->finger knee thigh 6 head->neck->shoulder->back->hip->thigh->knee leg knee 7 head->neck->shoulder->back->hip->thigh->knee->leg ankle leg 8 head->neck->shoulder->back->hip->thigh->knee->leg->ankle heel ankle 9 head->neck->shoulder->back->hip->thigh->knee->leg->ankle->heel foot heel 10 head->neck->shoulder->back->hip->thigh->knee->leg->ankle->heel->foot toe foot 11 head->neck->shoulder->back->hip->thigh->knee->leg->ankle->heel->foot->toe and we can use our generated the_level column to make a nice display just as we used the level pseudocolumn with CONNECT BY: WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree FROM skellarchy; BONE_TREE --------------------------- head neck shoulder back arm hip wrist a rib b rib c rib thigh finger knee leg ankle heel foot toe Now, the bones are coming out in a bit of a funny order for a skeleton. Instead of this: shoulder back arm hip wrist a rib b rib c rib thigh finger I want to see this: shoulder arm wrist finger back a rib b rib c rib hip thigh The rows are coming out in BREADTH FIRST ordering – meaning all siblings of ‘shoulder’ are printed before any children of ‘shoulder’. But I want to see them in DEPTH FIRST: going from shoulder to finger before we start on the backbone. WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SEARCH DEPTH FIRST BY bone SET bone_order SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree FROM skellarchy ORDER BY bone_order; BONE_TREE --------------------------- head neck shoulder arm wrist finger back a rib b rib c rib hip thigh knee leg ankle heel foot toe And now the result looks more like a proper skeleton. Now on to cycles. A cycle is a loop in the hierarchical data: a row is its own ancestor. To put a cycle in the example data, I made the skeleton bend over and connect the head to the toe: UPDATE skeleton SET connected_to_the='toe' WHERE bone='head'; And now if we try to run the query: ERROR at line 2: ORA-32044: cycle detected while executing recursive WITH query With the CONNECT BY syntax, we can use CONNECT BY NOCYCLE to run a query even when cycles exist, and the pseudocolumn CONNECT_BY_IS_CYCLE to help detect cycles. For recursive WITH, Oracle provides a CYCLE clause, which is a bit more powerful as it allows us to name the column which is cycling. WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SEARCH DEPTH FIRST BY bone SET bone_order CYCLE bone SET is_a_cycle TO 'Y' DEFAULT 'N' SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree, is_a_cycle FROM skellarchy --where is_a_cycle='N' ORDER BY bone_order; BONE_TREE I ------------------------------------------------------------ - head N neck N shoulder N arm N wrist N finger N back N a rib N b rib N c rib N hip N thigh N knee N leg N ankle N heel N foot N toe N head Y The query runs until the first cycle is detected, then stops. The CONNECT BY syntax does provide a nice pseudocolumn, CONNECT_BY_ISLEAF, which is 1 when a row has no further children, 0 otherwise. In my next post, I’ll look at emulating this pseudocolumn with recursive WITH. Republished with permission. Original URL: http://rdbms-insight.com/wp/?p=103 Full Article
v Recursive WITH, part III: IS_LEAF By www.orafaq.com Published On :: Mon, 13 Jun 2016 19:25:35 +0000 articles: SQL & PL/SQLThe CONNECT BY syntax provides a useful pseudocolumn, CONNECT_BY_ISLEAF, which identifies leaf nodes in the data: it’s 1 when a row has no further children, 0 otherwise. In this post, I’ll look at emulating this pseudocolumn using recursive WITH. Let’s continue with the example from my previous posts about hierarchical data: the skeleton from the old song “Dem Dry Bones”. UPDATE skeleton SET connected_to_the=NULL WHERE bone='head'; SELECT * FROM skeleton; BONE CONNECTED_TO_THE ---------------------------------------- ---------------------------------------- shoulder neck back shoulder hip back thigh hip knee thigh leg knee foot heel head neck head toe foot arm shoulder wrist arm ankle leg heel ankle finger wrist a rib back b rib back c rib back With CONNECT BY, we can use the CONNECT_BY_ISLEAF pseudocolumn to identify leaf nodes: SELECT bone, level, ltrim(sys_connect_by_path(bone,' -> '),' -> ') AS path FROM skeleton WHERE connect_by_isleaf=1 START WITH connected_to_the IS NULL CONNECT BY prior bone=connected_to_the ORDER siblings BY 1; BONE LEVEL PATH --------- ----- ----------------------------------------------------------------------------------------------- finger 6 head -> neck -> shoulder -> arm -> wrist -> finger a rib 5 head -> neck -> shoulder -> back -> a rib b rib 5 head -> neck -> shoulder -> back -> b rib c rib 5 head -> neck -> shoulder -> back -> c rib toe 12 head -> neck -> shoulder -> back -> hip -> thigh -> knee -> leg -> ankle -> heel -> foot -> toe This pseudocolumn takes a little more thought to replicate using recursive WITH than the LEVEL pseudocolumn and the SYS_CONNECT_BY_PATH, which, as we saw in my last post, fall naturally out of the recursion. We can imitate CONNECT_BY_ISLEAF by searching DEPTH FIRST and using the LEAD function to peek at the next row’s the_level value. If the next row’s level is higher than the current row, then it’s a child of the current row; otherwise, it’s not a child. Since, with DEPTH FIRST, all the children of a row come out before any siblings, if the next row isn’t a child, then the current row is a leaf. WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SEARCH DEPTH FIRST BY bone SET bone_order CYCLE bone SET is_a_cycle TO 'Y' DEFAULT 'N' SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree , the_level, lead(the_level) OVER (ORDER BY bone_order) AS next_level, CASE WHEN the_level < lead(the_level) OVER (ORDER BY bone_order) THEN NULL ELSE 'LEAF' END is_leaf FROM skellarchy ORDER BY bone_order; BONE_TREE THE_LEVEL NEXT_LEVEL IS_L --------------------------------------------- ---------- ---------- ---- head 0 1 neck 1 2 shoulder 2 3 arm 3 4 wrist 4 5 finger 5 3 LEAF back 3 4 a rib 4 4 LEAF b rib 4 4 LEAF c rib 4 4 LEAF hip 4 5 thigh 5 6 knee 6 7 leg 7 8 ankle 8 9 heel 9 10 foot 10 11 toe 11 LEAF Watch out for Cycles The first point of caution about this solution concerns cycles. In my last post, I had created a cycle by making the ‘head’ node’s parent the ‘toe’ node. If I’d left the cycle in the data, the toe node wouldn’t be a leaf any more, but this query would falsely identify the head as a leaf: UPDATE skeleton SET connected_to_the='toe' WHERE bone='head'; BONE_TREE THE_LEVEL NEXT_LEVEL IS_L --------------------------------------------- ---------- ---------- ---- head 0 1 neck 1 2 shoulder 2 3 arm 3 4 wrist 4 5 finger 5 3 LEAF back 3 4 a rib 4 4 LEAF b rib 4 4 LEAF c rib 4 4 LEAF hip 4 5 thigh 5 6 knee 6 7 leg 7 8 ankle 8 9 heel 9 10 foot 10 11 toe 11 12 head 12 LEAF 19 rows selected. This can be corrected for by adding WHERE IS_A_CYCLE=’N’ to the query. Respect the order of evaluation… A second point of caution: if I add a WHERE clause to the query that limits the number of levels, the last line of the resultset will always be identified as a leaf. WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SEARCH DEPTH FIRST BY bone SET bone_order CYCLE bone SET is_a_cycle TO 'Y' DEFAULT 'N' SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree , the_level, lead(the_level) OVER (ORDER BY bone_order) AS next_level, CASE WHEN the_level < lead(the_level) OVER (ORDER BY bone_order) THEN NULL ELSE 'LEAF' END is_leaf FROM skellarchy WHERE the_level < 8 ORDER BY bone_order; BONE_TREE THE_LEVEL NEXT_LEVEL IS_L ------------------------------------------------------------ ---------- ---------- ---- head 0 1 neck 1 2 shoulder 2 3 arm 3 4 wrist 4 5 finger 5 3 LEAF back 3 4 a rib 4 4 LEAF b rib 4 4 LEAF c rib 4 4 LEAF hip 4 5 thigh 5 6 knee 6 7 leg 7 LEAF <<<===== The leg is falsely identified as a leaf, and NEXT_LEVEL comes out as NULL, even though the ‘leg’ row has a child row. Why is that? It’s because this solution uses the LEAD analytic function. With analytic functions, WHERE clauses are evaluated before the analytic functions. Highlighting the relevant bits from the query: WITH skellarchy AS ...[recursive WITH subquery]... SELECT ... LEAD(the_level) OVER (ORDER BY bone_order) AS next_level ... --analytic function FROM skellarchy WHERE the_level < 8 ... --where clause To quote the documentation: Analytic functions compute an aggregate value based on a group of rows…. The group of rows is called a window and is defined by the analytic_clause. For each row, a sliding window of rows is defined. The window determines the range of rows used to perform the calculations for the current row…. Analytic functions are the last set of operations performed in a query except for the final ORDER BY clause. All joins and all WHERE, GROUP BY, and HAVING clauses are completed before the analytic functions are processed. In the query above, “where the_level < 8" will be evaluated before LEAD(the_level). The EXPLAIN PLAN shows this very clearly: ----------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 76 | 8 (25)| 00:00:01 | | 1 | WINDOW BUFFER | | 2 | 76 | 8 (25)| 00:00:01 | <<=== LEAD |* 2 | VIEW | | 2 | 76 | 8 (25)| 00:00:01 | <<=== filter("THE_LEVEL"<8) | 3 | UNION ALL (RECURSIVE WITH) DEPTH FIRST| | | | | | |* 4 | TABLE ACCESS FULL | SKELETON | 1 | 24 | 2 (0)| 00:00:01 | |* 5 | HASH JOIN | | 1 | 49 | 5 (20)| 00:00:01 | | 6 | RECURSIVE WITH PUMP | | | | | | | 7 | TABLE ACCESS FULL | SKELETON | 18 | 432 | 2 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("THE_LEVEL"<8) 4 - filter("BONE"='head') 5 - access("R"."BONE"="S"."CONNECTED_TO_THE") The WINDOW BUFFER (analytic window) is evaluated after the VIEW which filters on “THE_LEVEL”<8. So, "lead(the_level) over (order by bone_order)" will be null where the_level=7, and the 'leg' wrongly identified as a leaf node. What we actually want is for the analytic function LEAD to run over the whole resultset, and only then limit the results to show the levels 0-7. The obvious way to do this is to wrap the query in a second SELECT statement: SELECT * FROM ( WITH skellarchy (bone, parent, the_level) AS ( SELECT bone, connected_to_the, 0 FROM skeleton WHERE bone = 'head' UNION ALL SELECT s.bone, s.connected_to_the , r.the_level + 1 FROM skeleton s, skellarchy r WHERE r.bone = s.connected_to_the ) SEARCH DEPTH FIRST BY bone SET bone_order CYCLE bone SET is_a_cycle TO 'Y' DEFAULT 'N' SELECT lpad(' ',2*the_level, ' ') || bone AS bone_tree , the_level, lead(the_level) OVER (ORDER BY bone_order) AS next_level, CASE WHEN the_level < lead(the_level) OVER (ORDER BY bone_order) THEN NULL ELSE 'LEAF' END is_leaf FROM skellarchy ORDER BY bone_order ) WHERE the_level < 8; BONE_TREE THE_LEVEL NEXT_LEVEL IS_L ------------------------------------------------------------ ---------- ---------- ---- head 0 1 neck 1 2 shoulder 2 3 arm 3 4 wrist 4 5 finger 5 3 LEAF back 3 4 a rib 4 4 LEAF b rib 4 4 LEAF c rib 4 4 LEAF hip 4 5 thigh 5 6 knee 6 7 leg 7 8 Now, the analytic function in the inner query is evaluated first, before the WHERE clause in the outer query. We can see this in the EXPLAIN PLAN too, of course. Now the WINDOW BUFFER (analytic window) is evaluated before the VIEW with filter(“THE_LEVEL”<8) : ------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 2 | 4068 | 8 (25)| 00:00:01 | |* 1 | VIEW | | 2 | 4068 | 8 (25)| 00:00:01 | <<=== filter("THE_LEVEL"<8) | 2 | WINDOW BUFFER | | 2 | 76 | 8 (25)| 00:00:01 | <<=== LEAD | 3 | VIEW | | 2 | 76 | 8 (25)| 00:00:01 | | 4 | UNION ALL (RECURSIVE WITH) DEPTH FIRST| | | | | | |* 5 | TABLE ACCESS FULL | SKELETON | 1 | 24 | 2 (0)| 00:00:01 | |* 6 | HASH JOIN | | 1 | 49 | 5 (20)| 00:00:01 | | 7 | RECURSIVE WITH PUMP | | | | | | | 8 | TABLE ACCESS FULL | SKELETON | 18 | 432 | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("THE_LEVEL"<8) 5 - filter("BONE"='head') 6 - access("R"."BONE"="S"."CONNECTED_TO_THE") This is one case of the general point that, as Tom Kyte explains in this Ask Tom answer,“select analytic_function from t where CONDITION” is NOT THE SAME AS “select * from (select analytic_function from t) where CONDITION”. So, to sum up my last few posts, we can do everything that CONNECT BY can do with the 11g recursive WITH syntax. Plus, the recursive WITH syntax makes it easy to express simple recursive algorithms in SQL. Republished with permission. Original URL: http://rdbms-insight.com/wp/?p=135 Full Article
v NIP #20 Sunday... The Move By titsntoast.blogspot.com Published On :: Sun, 22 Jun 2008 19:05:00 +0000 This is the second week in a row that NIP Friday is being posted on Sunday. Lately my schedule on Friday has just been insane. It also appears that it won't be improving any time soon either. So, to simplify things, I've decided to just go ahead and change it from NIP Fridays to NIP Sundays.Only the day has changed. Everything else, including the boobs, nudity and public settings will all remain the same... ............ Full Article Boobs NIP
v Fireline Fused Cristal 0,06 mm nu voor maar € 10,00 By www.hengelspullen.nl Published On :: vri, 03 okt 2014 12:00:29 GMT Fireline Fused Cristal Merk: Berkley Lengte: 110 meter De nummer 1 transparante superlijn ter wereld. Kenmerken van de Fireline Fused Cristal: - 3x sterker dan een mono lijn - Ultiem gevoelig. - Schuurbestendig - Extreem sterk - Ook geschikt voor op de molen De lijnen zijn in drie verschillende diameters te verkrijgen. Iedere diameter heeft weer een andere draagkracht. Full Article
v Forellen Station Deluxe normaal €399,00 nu voor maar €320,00 By www.hengelspullen.nl Published On :: vri, 03 okt 2014 12:04:01 GMT Forellen Station deluxe Merk: TFT TFT heeft wederom een kwaliteitsproduct voor de forelvisser op de markt gebracht. De TFT forellen Station Deluxe. Een tas met vele mogelijkheden. Het station bestaat uit de volgende onderdelen: - 1 draagtas , hierin passen alle onderdelen - 1x een deegtablet hierin kunt u eenvoudig uw deegpotjes plaatsen, zo heeft ze bij de hand - 1 x een assdoosjes tablet ( op de afbeelding zijn ze verschillende kleuren, maar in het echt hebben ze allemaal een rode deksel) - 1 x een tackle tas :deze kleinere tas kunt u aan de voorzijde van het station plaatsen. - 1 x het staanderwerk, waarom heen ook een tas zit. In deze grote tas zitten een tweedeling. Genoeg ruimte dus om al uw hengelsportartikelen in op te bergen, en handig mee te nemen. Wilt u een filmpje over het forellen station bekijken? ( helaas alleen nog in het duits te vinden) https://www.youtube.com/watch?v=m8JUzhcUtVc Full Article
v Bosbaan Hengelsteun van € 4,95 nu voor maar € 3,75 By www.hengelspullen.nl Published On :: vri, 03 okt 2014 12:05:05 GMT Bosbaan Hengelsteun Merk: Livebait Inhoud: 2 stuks Deze bosbaan hengelsteunen van Livebait zijn alom bekend. Ze zijn erg gemakkelijk in gebruik. De bosbaan hengelsteunen zijn voorzien van scherpe punten aan de onderkant, hierdoor kunt u ze gemakkelijk in de grond plaatsen. De bosbaan hengelsteunen hebben een lengte van 50 centimeter. Full Article
v 7 Volt elektrische handschoenen van Gerbing By www.hengelspullen.nl Published On :: vri, 03 okt 2014 19:43:10 GMT 7V VERWARMDE HANDSCHOENEN Of je nu gaat skiën, paardrijden, hond uitlaten, fietsen of wat dan ook, het is nooit leuk als je het koud hebt. De handen zullen het eerste koud worden. Hiervoor hebben wij verschillende 7 volt verwarmde handschoenen ontwikkeld waardoor je met plezier de dingen doet die je leuk vindt. Ook mensen met een minder goede doorbloeding zullen merken dat onze verwarmde handschoenen een uitkomst zijn. Alle Gerbing 7 volt verwarmde handschoenen en andere kledingstukken uit het 7 volt assortiment worden standaard geleverd met 2 oplaadbare batterijen. Dat wil zeggen dat in tegenstelling tot onze 12 volt elektrisch verwarmde handschoenen, die standaard aangesloten worden op een motorvoertuigaccu, de 7 volt handschoenen alleen maar autonoom gedragen kunnen worden. Net als onze 12 volt verwarmde handschoenen zijn de 7 volt verwarmde handschoenen voorzien van het gepatenteerde micro wire (staaldraad). Dit draad is heel sterk en erg flexibel. Voor alle doeleinden heeft Gerbing handschoenen: S-7 verwarmde textiel handschoenen zijn te gebruiken voor o.a.skiën en fietsen vanwege de extra verstevigingen aan de binnenkant van de hand. De lederen O-7 verwarmde handschoenen en de H-7 verwarmde handschoenen zijn weer te gebruiken voor diverse outdoor activiteiten. Zo is de H-7 handschoenen speciaal gemaakt voor paardrijden en jagen. Maar vanwege zijn sjieke uiterlijk kan men ook leeker verwarmt rijden in een cabrio. De M-7 verwarmde wanten maken de collectie compleet. Deze textiele wanten zijn verkrijgbaar in drie maten en zijn voor heel veel activiteiten geschikt. Al deze 7 volt verwarmde handschoenen worden geleverd met een 7 volt batterij kitje (B7V-2500 KIT). Deze batterijen worden ook voor de 7 volt verwarmde jassen, 7 volt verwarmde sokken en alle overige 7 volt producten. De batterijen zijn eenvoudig te bedienen en zorgen voor uren plezier met warme handen. Full Article