rank over in mysql - sql

I read this article, and i have the code in oracle, but I want to convert it to work on MySQL. In Oracle, i use the function rank, with four columns can eligible or not, how i can use this in mysql, or, it is not possible?
This is the code, I want select the most eligible line, every line can have 4 columns completed, I want to rank one of which has more data.
SELECT vlr,
data
INTO vn_vlr,
vd_data
FROM (SELECT a.*, rank() over (ORDER BY nvl(a.id_categoria, -1) DESC,
nvl(a.id_peso, -1) DESC,
nvl(a.id_faixa, -1) DESC,
nvl(a.sexo, ' ') DESC ) rank
FROM tab_regra_pagamento a
WHERE a.id_competicao = pidcompedticao
AND a.tipo = 'NORMAL'
AND a.data_vencimento > SYSDATE
AND nvl(a.id_categoria, vid_categoria) = vid_categoria
AND nvl(a.id_faixa, vid_faixa) = vid_faixa
AND nvl(a.id_peso, vid_peso) = vid_peso
AND nvl(a.sexo, vsexo) = vsexo)
WHERE rank = 1;

SELECT #rank := #rank + (#value <> value),
#value := value
FROM (
SELECT #rank := 0,
#value := -1
) vars,
mytable
ORDER BY
value
In you case, when you just need all copies of the first set of values:
SELECT vlr, data
FROM tab_regra_pagamento a
WHERE a.id_competicao = pidcompedticao
AND a.tipo = 'NORMAL'
AND a.data_vencimento > SYSDATE
AND (a.id_cetegoria, a.id_faixa, a.id_peso, a.sexo) =
(
SELECT ai.id_cetegoria, ai.id_faixa, ai.id_peso, ai.sexo
FROM tab_regra_pagamento ai
WHERE ai.id_competicao = pidcompedticao
AND ai.tipo = 'NORMAL'
AND ai.data_vencimento > SYSDATE
ORDER BY
a.id_cetegoria DESC, a.id_faixa DESC, a.id_peso DESC, a.sexo DESC
LIMIT 1
)

Related

using ROWNUM TOP-N

why the external fields canĀ“t be used in these subquery?
SELECT d1_cod,
D1_VUNIT,
(
SELECT sd2.d1_vunit from (select d1_filial,d1_vunit,d1_emissao,d1_cod,d1_doc)
FROM sd1160 sd12
WHERE sd12.D1_EMISSAO < **x.d1_emissao**
And sd12.D1_FILIAL = **x.d1_filial**
And sd12.D1_COD = **x.d1_cod**
And sd12.D_E_L_E_T_ = ' '
ORDER BY sd12.d1_emissao DESC)
Where ROWNUM < 2)
FROM sd1160 x
WHERE x.D_E_L_E_T_ = ' '
AND x.d1_emissao = '20160808'
ORDER BY x.d1_emissao DESC
)
Thanks
Oracle only recognizes correlated references one-level deep. One way around this is to use the keep syntax:
SELECT d1_cod,
D1_VUNIT,
(SELECT MAX(st12.d1_vunit) KEEP (DENSE_RANK FIRST ORDER BY sd12.d1_emissao DESC)
FROM sd1160 sd12
WHERE sd12.D1_EMISSAO < **x.d1_emissao** AND
sd12.D1_FILIAL = **x.d1_filial** AND
sd12.D1_COD = **x.d1_cod** AND
sd12.D_E_L_E_T_ = ' '
)
FROM sd1160 x
WHERE x.D_E_L_E_T_ = ' ' AND x.d1_emissao = '20160808'
ORDER BY x.d1_emissao DESC;

Translating SQL Server 'OUTPUT' to Oracle?

I am having big issues translating my MSSQL (sql-server) query to Oracle (PL-SQL).
The goal is to do an update and a select on the updated field in one threadsafe operation.
My current MSSQL query:
UPDATE PDFCONVERT_G
SET PDF_STATUS = 1, PDF_STARTDATE = GETDATE(), PDF_CONVERTERNAME='inputConverterName'
OUTPUT Inserted.PDF_ACTION as Action,
Inserted.PDF_ARKMERK_VE As ARKMERK,
Inserted.PDF_TYPE_DL as DlTypeDT,
Inserted.PDF_DOKID_VE as DocId,
Inserted.PDF_DOKMALID_VE as DOKMALID,
Inserted.PDF_FILREF_VE as FILREF,
Inserted.PDF_FILTYPE_LF as Filtype,
Inserted.PDF_JPID_JP as JpId,
Inserted.PDF_LOCFILREF_VE as LOCFILREF,
Inserted.PDF_SAID_SA as SaId,
Inserted.PDF_SJEKKETUT_VE as SJEKKETUT,
Inserted.PDF_TGKODE_VE as TGKODE,
Inserted.PDF_VARIANT_VE as Variant,
Inserted.PDF_VERSJON_VE as Version,
Inserted.PDF_CHECKINAFTERCONVERT as CheckinAfterConvert
FROM PDFCONVERT_G t1
INNER JOIN (
SELECT TOP(1) *
FROM PDFCONVERT_G A WHERE (
(A.PDF_LAGRENH_VE = 'PROD' OR EXISTS(SELECT * FROM PDFCONVERT_G B WHERE A.PDF_JOBID=B.PDF_JOBID AND B.PDF_LAGRENH_VE='PROD' AND B.PDF_ACTION='MERGE'))
AND PDF_STATUS = 0 AND NOT EXISTS(
SELECT * FROM PDFCONVERT_G B where a.pdf_jobid = b.pdf_jobid and b.pdf_status > 0 and a.pdf_action != b.pdf_action))
ORDER BY A.PDF_PRIORITY DESC, A.PDF_JOBID, A.PDF_RNR
) t2 ON t2.PDF_JOBID = t1.PDF_JOBID
I can simply do this query in my .net code and the result will be the Output variables.
I know Oracle has the RETURNING INTO syntax but concidering how complex my WHERE clause is I simply get syntax errors all the time.
I would prefer to write a query without creating a function but even if I have to do that, I am having issues.
SELECT TOP(1) *
FROM PDFCONVERT_G A
WHERE (
( A.PDF_LAGRENH_VE = 'PROD'
OR EXISTS(SELECT *
FROM PDFCONVERT_G B
WHERE A.PDF_JOBID=B.PDF_JOBID
AND B.PDF_LAGRENH_VE='PROD'
AND B.PDF_ACTION='MERGE')
)
AND PDF_STATUS = 0
AND NOT EXISTS(
SELECT *
FROM PDFCONVERT_G B
where a.pdf_jobid = b.pdf_jobid
and b.pdf_status > 0
and a.pdf_action != b.pdf_action
)
)
ORDER BY A.PDF_PRIORITY DESC, A.PDF_JOBID, A.PDF_RNR
Can be rewritten (without the correlated sub-queries) as:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER ( ORDER BY PDF_PRIORITY DESC, PDF_JOBID, PDF_RNR ) AS rn
FROM (
SELECT a.*,
COUNT(
CASE WHEN DF_LAGRENH_VE = 'PROD'
AND PDF_ACTION = 'MERGE'
THEN 1 END
) OVER ( PARTITION BY pdf_jobid )
AS num_prod_merge,
COUNT(
CASE WHEN pdf_status > 0 THEN 1 END
) OVER ( PARTITION BY pdf_jobid )
AS num_all_actions,
COUNT(
CASE WHEN pdf_status > 0 THEN 1 END
) OVER ( PARTITION BY pdf_jobid, pdf_action )
AS num_same_actions
FROM PDFCONVERT_G a
) a
WHERE ( PDF_LAGRENH_VE = 'PROD' OR num_prod_merge > 0 )
AND PDF_STATUS = 0
AND num_all_actions = num_same_actions
)
WHERE rn = 1;
You can then rewrite your UPDATE to something like:
UPDATE PDFCONVERT_G
SET PDF_STATUS = 1,
PDF_STARTDATE = SYSDATE,
PDF_CONVERTERNAME='inputConverterName'
WHERE ROWID = (
SELECT ROWID
FROM (
-- as above
)
WHERE rn = 1
)
RETURNING PDF_ACTION -- , ...
INTO :Action -- , ...
(Note: Unable to test this at the moment so there may be some small syntax errors but you should get the general idea.)

What is the issue with this CTE WITH clause in PL SQL /Oracle?

I have below query.
The below query WITH CTE, it is returning 4 Records.
As I gave the comments, the below Select query has 55 Records and with And clause it should remove those 4 Records and return 51 records. Instead it is returning simply those 4 records only.
Just for testing I commented that AND clause and then it is functioning as expected and returning 55+4 = total of 59 Records.
How to fix this WITH CTE. What is wrong?
CREATE OR REPLACE PROCEDURE CUSTCONNECT.sp_GetPodConfigurationGridData(
p_podURL IN varchar2, --PodUrl
p_serverType IN varchar2,
p_serverName IN varchar2,
p_publishedDate IN date,
P_RECORDSET OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN P_RECORDSET FOR
--This has total of 4 Records
WITH PodServerRecords(Key, value, Overwrite, ServerName, ServerType, PublishDate ) AS (
select
PC.KeyId as Key, KeyIdValue as value, 'Pod' as Overwrite, '' as ServerName, '' as Servertype, PC.PublishDate
from (select
Keylog.*, row_number() over (partition by Keylog.KeyId order by Keylog.PublishDate desc) as RowNu
from PodConfigLog_Tab Keylog
where Keylog.URL = p_podURL
and Keylog.PublishDate >= p_publishedDate and Keylog.PublishDate <= sysdate
) PC
where PC.RowNu = 1 and PC.IsActive = 'T'
UNION
select
PCBS.KeyId as Key, KeyIdValue as value, 'Server' as Overwrite, PCBS.ServerName, Servertype, PCBS.PublishDate
from (select
Serlog.*, PS.ServerType, row_number() over (partition by Serlog.KeyId order by Serlog.PublishDate desc) as RowNu
from PodConfigByServerLog_Tab Serlog
join PodServer_tab PS on PS.ServerName = Serlog.ServerName
and Serlog.URL = PS.URL
where Serlog.URL = p_podURL
and Serlog.ServerName = p_serverName
and Serlog.PublishDate >= p_publishedDate and Serlog.PublishDate <= sysdate
) PCBS
where PCBS.RowNu = 1 and PCBS.IsActive = 'T'
)
--This has total of 55 Records
select
PCK.KeyId as Key ,DefaultKeyIdValue as value,'Default' as Overwrite, '' as ServerName, '' as Servertype, PCK.PublishDate
from
(select
Keylog.*, row_number() over (partition by Keylog.KeyId order by Keylog.PublishDate desc) as RowNu
from PodConfigKeyLog_Tab Keylog
where Keylog.PublishDate >= p_publishedDate and Keylog.PublishDate <= sysdate
) PCK
join POD_TAB PS on PS.URL = p_podURL
where PCK.RowNu = 1 and PCK.IsActive = 'T'
--This And caluse should remove those 4 Records and total Records should be 51.
and PCK.KeyId not in (
select KeyId
from PodServerRecords
)
UNION
--This is total of 4 Records
SELECT
Key, value, Overwrite, ServerName, ServerType, PublishDate
FROM PodServerRecords
Order By Key;
END;
/
Your problem is that the CTE does not have a column called KeyId. You renamed it to Key. However, NOT IN has unexpected behavior when there are NULL values. You can fix this by eliminating them directly:
PCK.KeyId not in (
select psr.KeyId
from PodServerRecords psr
where psr.KeyId IS NOT NULL
)
I recommend using NOT EXISTS instead:
NOT EXISTS (select 1
from PodServerRecords psr
where psr.KeyId = PCK.KeyId
)
This may fix your problem.
Actually, I don't see a KeyId in your CTE. So, I think you want:
NOT EXISTS (select 1
from PodServerRecords psr
where psr.Key = PCK.KeyId
)
Note the preceding statements will return errors, indicating that the problem is the misnamed column.
I think you should remove that UNION part of your query cause it's readding those 4 records from PodServerRecords. Your query should rather be
--This has total of 55 Records
select
PCK.KeyId as Key ,DefaultKeyIdValue as value,'Default' as Overwrite, '' as ServerName, '' as Servertype, PCK.PublishDate
from
(select
Keylog.*, row_number() over (partition by Keylog.KeyId order by Keylog.PublishDate desc) as RowNu
from PodConfigKeyLog_Tab Keylog
where Keylog.PublishDate >= p_publishedDate and Keylog.PublishDate <= sysdate
) PCK
join POD_TAB PS on PS.URL = p_podURL
where PCK.RowNu = 1 and PCK.IsActive = 'T'
--This And caluse should remove those 4 Records and total Records should be 51.
and PCK.KeyId not in (
select KeyId
from PodServerRecords
);

Oracle SQL Group by Clause

I would like to write a sql to get top 5 table space storage metric. Below query gives the metric about all tbspaces. Appreciate if someone fine tune this to have only top N
SELECT
ts.tablespace_name AS TBNAME,
round((ts.tablespace_size/1024/1024),2) AS SIZE_MB,
round((ts.tablespace_used_size/1024/1024),2) AS USED_MB,
round(((ts.tablespace_size - ts.tablespace_used_size)/1024/1024),2) AS FREE_MB
FROM
mgmt$db_tablespaces ts,
(SELECT d.target_guid, d.tablespace_name, count(d.file_name) df_count,
sum(decode(d.autoextensible, 'YES', 1, 0)) auto_extend
FROM mgmt$db_datafiles d, mgmt$target t
WHERE t.target_guid = '<id>' AND
(t.target_type='rac_database' OR
(t.target_type='oracle_database' AND t.TYPE_QUALIFIER3 != 'RACINST')) AND
t.target_guid = d.target_guid
GROUP BY d.target_guid, d.tablespace_name) df
WHERE
ts.target_guid = df.target_guid AND
df.tablespace_name = ts.tablespace_name
ORDER BY ts.tablespace_size;`
Thanks
You can use the ROWNUM. Oracle applies rownum to the result after it has been returned.
You need to filter the result after it has been returned, so a subquery is required. You can also use RANK() function to get Top-N results.
SELECT
*
FROM
(
SELECT
ts.tablespace_name AS TBNAME,
round((ts.tablespace_size/1024/1024),2) AS SIZE_MB,
round((ts.tablespace_used_size/1024/1024),2) AS USED_MB,
round(((ts.tablespace_size - ts.tablespace_used_size)/1024/1024),2) AS FREE_MB
FROM
mgmt$db_tablespaces ts,
(SELECT d.target_guid, d.tablespace_name, count(d.file_name) df_count,
sum(decode(d.autoextensible, 'YES', 1, 0)) auto_extend
FROM mgmt$db_datafiles d, mgmt$target t
WHERE t.target_guid = '<id>' AND
(t.target_type='rac_database' OR
(t.target_type='oracle_database' AND t.TYPE_QUALIFIER3 != 'RACINST')) AND
t.target_guid = d.target_guid
GROUP BY d.target_guid, d.tablespace_name) df
WHERE
ts.target_guid = df.target_guid AND
df.tablespace_name = ts.tablespace_name
ORDER BY ts.tablespace_size
)
WHERE ROWNUM <= 5;

Trying to Show The records with the most recent Date

Im trying to use the Over Partition to create a row number based on SupplierAccountNumber then Sort by DateTimeCreated and then only show record 1. my current script i get an error saying Invalid column name 'RowNum'??
I have a list of email addresses for suppliers which have multiple addresses, i only want to pick out the most recent email address. Is there a better way of doing it?
SELECT plsuppliercontact.plsuppliercontactid,
plsupplieraccount.supplieraccountnumber,
plsupplieraccount.supplieraccountname,
plsupplieraccount.supplieraccountshortname,
plsuppliercontactvalue.contactvalue,
syscontacttype.name,
Rownum = Row_number()
OVER(
partition BY plsupplieraccount.supplieraccountnumber
ORDER BY plsuppliercontactvalue.datetimecreated DESC)
FROM alops.dbo.plsupplieraccount PLSupplierAccount,
alops.dbo.plsuppliercontact PLSupplierContact,
alops.dbo.plsuppliercontactvalue PLSupplierContactValue,
alops.dbo.syscontacttype SYSContactType
WHERE plsupplieraccount.plsupplieraccountid =
plsuppliercontact.plsupplieraccountid
AND plsuppliercontactvalue.plsuppliercontactid =
plsuppliercontact.plsuppliercontactid
AND syscontacttype.syscontacttypeid =
plsuppliercontactvalue.syscontacttypeid
AND (( syscontacttype.name = 'E-mail Address' ))
AND rownum = 1;
You didn't specify with RDBMS you were using, but most of them only apply aliases after the query is executed.
One trick is to wrap the query in an another query that takes care of this condition. E.g.:
SELECT *
FROM (
SELECT plsuppliercontact.plsuppliercontactid,
plsupplieraccount.supplieraccountnumber,
plsupplieraccount.supplieraccountname,
plsupplieraccount.supplieraccountshortname,
plsuppliercontactvalue.contactvalue,
syscontacttype.name,
Rownum = Row_number()
OVER(
partition BY plsupplieraccount.supplieraccountnumber
ORDER BY plsuppliercontactvalue.datetimecreated DESC)
FROM alops.dbo.plsupplieraccount PLSupplierAccount,
alops.dbo.plsuppliercontact PLSupplierContact,
alops.dbo.plsuppliercontactvalue PLSupplierContactValue,
alops.dbo.syscontacttype SYSContactType
WHERE plsupplieraccount.plsupplieraccountid =
plsuppliercontact.plsupplieraccountid
AND plsuppliercontactvalue.plsuppliercontactid =
plsuppliercontact.plsuppliercontactid
AND syscontacttype.syscontacttypeid =
plsuppliercontactvalue.syscontacttypeid
AND (( syscontacttype.name = 'E-mail Address' ))
)
WHERE rownum = 1;
Use the MAX aggregate
SELECT plsuppliercontact.plsuppliercontactid,
plsupplieraccount.supplieraccountnumber,
plsupplieraccount.supplieraccountname,
plsupplieraccount.supplieraccountshortname,
plsuppliercontactvalue.contactvalue,
syscontacttype.name,
MAX(plsuppliercontactvalue.datetimecreated)
FROM alops.dbo.plsupplieraccount PLSupplierAccount,
alops.dbo.plsuppliercontact PLSupplierContact,
alops.dbo.plsuppliercontactvalue PLSupplierContactValue,
alops.dbo.syscontacttype SYSContactType
WHERE plsupplieraccount.plsupplieraccountid =
plsuppliercontact.plsupplieraccountid
AND plsuppliercontactvalue.plsuppliercontactid =
plsuppliercontact.plsuppliercontactid
AND syscontacttype.syscontacttypeid =
plsuppliercontactvalue.syscontacttypeid
AND (( syscontacttype.name = 'E-mail Address' ))
GROUP BY plsuppliercontact.plsuppliercontactid,
plsupplieraccount.supplieraccountnumber,
plsupplieraccount.supplieraccountname,
plsupplieraccount.supplieraccountshortname,
plsuppliercontactvalue.contactvalue,
syscontacttype.name