Question

I'm trying to convert the above script from MySQL to ORACLE and I'm total beginner using ORACLE Database and PL/SQL. I read that IFNULL in MYSQL is equivalent to NVL in ORACLE, but still I cannot convert the beyond script. Please help.

SET @r:=0;

CREATE TABLE COUNTRY_MONDIAL AS 
SELECT @r:=@r+1 RowN, @Dtf0:=Dtf0 Dtf0, @Dtf1:=Dtf1 Dtf1, 
IFNULL((log(log(@Dtf0)+1)+1),0)*9.531408863445597 + 
IFNULL((log(log(@Dtf1)+1)+1),0)*9.531408863445696 Score, Id,ID_CITY, Id, dl 
FROM (SELECT PKey, MAX(CASE WHEN WordId=205 THEN Count ELSE 0 END) AS Dtf0, 
MAX(CASE WHEN WordId=223 THEN Count ELSE 0 END) AS Dtf1 
FROM COUNTRY_I WHERE WordId in (205,223) 
GROUP BY PKey HAVING Dtf0>0 OR Dtf1>0) Cnt, COUNTRY T1 
WHERE Cnt.PKey = Id
ORDER BY Score DESC;

Thanks in Advance.

Was it helpful?

Solution

Here's what I came up with (this isn't tested yet)

CREATE TABLE COUNTRY_MONDIAL 
AS 
SELECT ROW_NUMBER() OVER (ORDER BY t.Score DESC) AS RowN
     , c.Dtf0
     , c.Dtf1
     , COALESCE((LOG(LOG(c.Dtf0)+1)+1),0)*9.531408863445597 
       + COALESCE((LOG(LOG(c.Dtf1)+1)+1), 0)*9.531408863445696 AS Score
     , t.Id
     , t.ID_CITY
     , t.Id AS Id2
     , t.dl
  FROM ( SELECT i.PKey
              , MAX(CASE WHEN i.WordId=205 THEN i.COUNT ELSE 0 END) AS Dtf0
              , MAX(CASE WHEN i.WordId=223 THEN i.COUNT ELSE 0 END) AS Dtf1
           FROM COUNTRY_I i
          WHERE i.WordId IN (205,223)
          GROUP
             BY i.PKey
         HAVING 0 < MAX(CASE WHEN i.WordId=205 THEN i.COUNT ELSE 0 END)
             OR 0 < MAX(CASE WHEN i.WordId=223 THEN i.COUNT ELSE 0 END)
       ) c
  JOIN COUNTRY t
    ON t.Id = c.PKey
 ORDER
    BY t.Score DESC;

Some notes:

I don't believe you can reference an alias assigned to an expression in a HAVING clause. (This may have changed, and now be allowed in more recent versions of Oracle, but in the HAVING clause, we had to repeat the expression.

An alias CAN be referenced in an ORDER BY clause (except for UNION/UNION ALL queries); we

We can always reference by column position in the SELECT list.

I'm not sure if we can reference the column alias in the ORDER BY clause, in the ROW_NUMBER() OVER(). The query above does that, but repeating that expression would be the workaround.

Qualifying ALL column references with a table alias is good practice.

We can't have two columns of the same name (Id) in a table, so at least one of the occurrences will need to be assigned a different name, its better to specify it in our query (we avoid Oracle throwing an error, or from generating an assigned name.)

In the query above, the COALESCE function performs the same duties as NVL() or CASE expression. (I believe COALESCE is the more portable and SQL-92 compatible option.)

I think COUNT is a keyword, qualifying it with a table alias (i.COUNT) makes it unambiguous.

OTHER TIPS

It looks to me like the variable @r is being used to create a sequential number, which in Oracle could be replaced with a sequence. Try the following:

CREATE SEQUENCE COUNTRY_MONDIAL_SEQ
  MINVALUE 1
  NOMAXVALUE 
  NOCACHE;

CREATE TABLE COUNTRY_MONDIAL AS
  SELECT COUNTRY_MONDAIL_SEQ.NEXTVAL AS ROWN,
         cnt.DTF0,
         cnt.DTF1,
         NVL(LOG(LOG(cnt.DTF0)+1)+1, 0) * 9.531408863445597 +
           NVL(LOG(LOG(cnt.DTF1)+1)+1, 0) *9 .531408863445696 AS SCORE,
         t1.ID,
         t1.ID_CITY,
         t1.ID,
         t1.DL
    FROM (SELECT PKEY,
                 MAX(CASE WHEN WORDID = 205 THEN COUNT ELSE 0 END) AS DTF0,
                 MAX(CASE WHEN WORDID = 223 THEN COUNT ELSE 0 END) AS DTF1,
            FROM COUNTRY_I
            WHERE WORDID IN (205, 223)
            GROUP BY PKEY
            HAVING DTF0 > 0 OR
                   DTF1 > 0) cnt
     INNER JOIN COUNTRY t1
       ON (t1.ID = cnt.PKEY)
     ORDER BY SCORE DESC;

Share and enjoy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top