Custom row number in SQL - sql

I am using a software which doesn't have a feature on custom row number. In order to resolve my issue, I have to tweak it on my SQL and create a custom column for the custom row number. Here is what I want to do as my custom row number along with my select statement:
li{
list-style-type: none;
}
<ul>
<li>1.</li>
<li>2.</li>
<li>2.1</li>
<li>2.2</li>
<li>2.3</li>
<li>3.</li>
<li>3.1</li>
<li>3.2</li>
</ul>
I am using Microsoft SQL Server. I tried to use variables but it doesn't work the way I wanted to be. Here is my sample faulty output:
SELECT chart.col1,CASE
WHEN chart.CHART_LEVEL <= 2 THEN #no += 1
WHEN chart.CHART_LEVEL => 3 THEN CONCAT(#no,'.'#subNo += 1)
ELSE ''
END
AS 'RowNo'
FROM myTable chart
I am really sorry for giving insufficient details.

If you have a column in that table, that defines an order, you could get the section numbers with subqueries fetching the count of rows with lower ordered rows with the respective level.
Assuming the column defining the order is id something looking like this could be what you want.
SELECT col1,
convert(varchar(max), (SELECT count(*)
FROM myTable chart1
WHERE chart1.id <= chart.id
AND chart1.chart_level <= 2))
+
CASE
WHEN (SELECT count(*)
FROM myTable chart2
WHERE chart2.id <= chart.id
AND chart2.chart_level > 2
AND (SELECT count(*)
FROM myTable chart3
WHERE chart3.id <= chart.id
AND chart3.chart_level <= 2)
= (SELECT count(*)
FROM myTable chart4
WHERE chart4.id <= chart2.id
AND chart4.chart_level <= 2)) = 0
THEN ''
ELSE
'.' + convert(varchar(max), (SELECT count(*)
FROM myTable chart2
WHERE chart2.id <= chart.id
AND chart2.chart_level > 2
AND (SELECT count(*)
FROM myTable chart3
WHERE chart3.id <= chart.id
AND chart3.chart_level <= 2)
= (SELECT count(*)
FROM myTable chart4
WHERE chart4.id <= chart2.id
AND chart4.chart_level <= 2)))
END RowNo
FROM myTable chart;

Related

Subquery Building a Column

I am wondering if there is a more efficient way of doing the following query.
SELECT
t.iCertification_UserCertificationTranscriptID AS I_CERT_TRANSCRIPT_DIM,
t.iHR_UserID AS I_EMP_DIM,
t.iCertification_CertificationID AS I_RUL_CERT_DIM,
(
SELECT iHR_PositionID
FROM UserProfileNoGroups AS prof
WHERE
(iHR_UserID = t.iHR_UserID)
AND (Profile_IsPrimary = '1')
AND (UserPosition_IsPrimary = '1')
AND (t.dEffectiveStart BETWEEN UserPosition_Effective AND COALESCE(UserPosition_End, LOCALTIMESTAMP))
ORDER BY UserPosition_Effective DESC
FETCH FIRST 1 ROWS ONLY
) AS I_POSN_DIM,
CAST(EXTRACT(YEAR FROM t.dEffectiveStart) * 10000 + EXTRACT(MONTH FROM t.dEffectiveStart) * 100 + EXTRACT(DAY FROM t.dEffectiveStart) AS INT) AS I_DAY_STRT_DIM,
CAST(EXTRACT(YEAR FROM t.dEffectiveEnd) * 10000 + EXTRACT(MONTH FROM t.dEffectiveEnd) * 100 + EXTRACT(DAY FROM t.dEffectiveEnd) AS INT) AS I_DAY_END_DIM,
CASE
WHEN t.iCertification_TranscriptSourceID = '1' THEN 'Y'
ELSE 'N'
END AS L_AdminOverride,
t.mComment AS X_Comment
FROM
dbo.tCertification_UCT AS t;
I am concerned of the query that builds column I_POSN_DIM. The query performs slowly and it seems like that query has to be scanned over and over to extract results. This is in postgresql and I am not that familiar with this platform. I tried using CTEs that uses the MAX function, but the COUNT always turns out different from this query. Any assistance would be appreaciated.
I thought something like this:
SELECT
t.iCertification_UserCertificationTranscriptID AS I_CERT_TRANSCRIPT_DIM,
t.iHR_UserID AS I_EMP_DIM,
t.iCertification_CertificationID AS I_RUL_CERT_DIM,
uPG.iHR_PositionID AS I_POSN_DIM,
(t.dEffectiveStart.Year * 10000 + t.dEffectiveStart.Month * 100 + t.dEffectiveStart.Day) AS I_DAY_STRT_DIM,
(t.dEffectiveEnd.Year * 10000 + t.dEffectiveEnd.Month * 100 + t.dEffectiveEnd.Day) AS I_DAY_END_DIM,
CASE WHEN t.iCertification_TranscriptSourceID = '1' THEN 'Y' ELSE 'N' END AS L_AdminOverride,
t.mComment AS X_Comment
FROM dbo.tCertification_UCT AS t
INNER JOIN UserProfileNoGroups uPG ON t.iHR_UserID = uPG.iHR_UserID
WHERE Profile_IsPrimary = '1'
AND UserPosition_IsPrimary = '1'
AND (t.dEffectiveStart BETWEEN UserPosition_Effective AND COALESCE(UserPosition_End, LOCALTIMESTAMP));
I moved the inner query to outside and I convert it in an equivalent inner join. In others fields you did cast but it's not neccesary because of the result from that operations is an int.
But I supossed that table UserProfileNoGroups has 1 record for each record at tCertification_UCT. If it's not this way, the query would change a litlle:
SELECT
t.iCertification_UserCertificationTranscriptID AS I_CERT_TRANSCRIPT_DIM,
t.iHR_UserID AS I_EMP_DIM,
t.iCertification_CertificationID AS I_RUL_CERT_DIM,
uPG.iHR_PositionID OVER (ORDER BY UserPosition_Effective DESC) AS I_POSN_DIM,
(t.dEffectiveStart.Year * 10000 + t.dEffectiveStart.Month * 100 + t.dEffectiveStart.Day) AS I_DAY_STRT_DIM,
(t.dEffectiveEnd.Year * 10000 + t.dEffectiveEnd.Month * 100 + t.dEffectiveEnd.Day) AS I_DAY_END_DIM,
CASE WHEN t.iCertification_TranscriptSourceID = '1' THEN 'Y' ELSE 'N' END AS L_AdminOverride,
t.mComment AS X_Comment
FROM dbo.tCertification_UCT AS t
INNER JOIN UserProfileNoGroups uPG ON t.iHR_UserID = uPG.iHR_UserID
WHERE Profile_IsPrimary = '1'
AND UserPosition_IsPrimary = '1'
AND (t.dEffectiveStart BETWEEN UserPosition_Effective AND COALESCE(UserPosition_End, LOCALTIMESTAMP));
You can play with OVER clause:
https://www.postgresql.org/docs/9.1/tutorial-window.html

troubles with next and previous query

I have a list and the returned table looks like this. I took the preview of only one car but there are many more.
What I need to do now is check that the current KM value is larger then the previous and smaller then the next. If this is not the case I need to make a field called Trustworthy and should fill it with either 1 or 0 (true/ false).
The result that I have so far is this:
validKMstand and validkmstand2 are how I calculate it. It did not work in one list so that is why I separated it.
In both of my tries my code does not work.
Here is the code that I have so far.
FullList as (
SELECT
*
FROM
eMK_Mileage as Mileage
)
, ValidChecked1 as (
SELECT
UL1.*,
CASE WHEN EXISTS(
SELECT TOP(1)UL2.*
FROM FullList AS UL2
WHERE
UL2.FK_CarID = UL1.FK_CarID AND
UL1.KM_Date > UL2.KM_Date AND
UL1.KM > UL2.KM
ORDER BY UL2.KM_Date DESC
)
THEN 1
ELSE 0
END AS validkmstand
FROM FullList as UL1
)
, ValidChecked2 as (
SELECT
List1.*,
(CASE WHEN List1.KM > ulprev.KM
THEN 1
ELSE 0
END
) AS validkmstand2
FROM ValidChecked1 as List1 outer apply
(SELECT TOP(1)UL3.*
FROM ValidChecked1 AS UL3
WHERE
UL3.FK_CarID = List1.FK_CarID AND
UL3.KM_Date <= List1.KM_Date AND
List1.KM > UL3.KM
ORDER BY UL3.KM_Date DESC) ulprev
)
SELECT * FROM ValidChecked2 order by FK_CarID, KM_Date
Maybe something like this is what you are looking for?
;with data as
(
select *, rn = row_number() over (partition by fk_carid order by km_date)
from eMK_Mileage
)
select
d.FK_CarID, d.KM, d.KM_Date,
valid =
case
when (d.KM > d_prev.KM /* or d_prev.KM is null */)
and (d.KM < d_next.KM /* or d_next.KM is null */)
then 1 else 0
end
from data d
left join data d_prev on d.FK_CarID = d_prev.FK_CarID and d_prev.rn = d.rn - 1
left join data d_next on d.FK_CarID = d_next.FK_CarID and d_next.rn = d.rn + 1
order by d.FK_CarID, d.KM_Date
With SQL Server versions 2012+ you could have used the lag() and lead() analytical functions to access the previous/next rows, but in versions before you can accomplish the same thing by numbering rows within partitions of the set. There are other ways too, like using correlated subqueries.
I left a couple of conditions commented out that deal with the first and last rows for every car - maybe those should be considered valid is they fulfill only one part of the comparison (since the previous/next rows are null)?

Need to get the column from the table in exists clause

I have a query below:
SELECT AIDI.LOAN_NUM, AIDI.LOCATION_CODE, AIDI.ORD_NUM, AIDI.MTN, AIDI.LOAN_STATUS, COUNT(*)
FROM table1 AIDI
WHERE AIDI.LOAN_STATUS = 'A'
AND EXISTS (SELECT 1 FROM ORDERS AO
WHERE AO.ACE_ORD_NUM = AIDI.ORD_NUM
AND AO.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND AO.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE))
GROUP BY AIDI.LOAN_NUM, AIDI.LOCATION_CODE, AIDI.ORD_NUM, AIDI.MTN, AIDI.LOAN_STATUS
HAVING COUNT(*) > 1;
I need to get the AO.ACE_ORD_COMPLETION_TIME this column into select clause so that i can see the date also in the result set.

Oracle: get X rows from point A

I have a stored procedure which gets a list of items attached to a given configuration (each item is attached to one configuration ; if it's not (i.e. the field is NULL) then we consider it attaced to the default configuration (wich has its field ISDEFAULT to 1). I would like to get the items using pagination. I remembered that the ROWNUM field starts at one, so I wrote (using 0 for the first page, and ten items per page):
SELECT *
FROM
ITEMS item
WHERE
(ROWNUM - 1) >= 0 and
(ROWNUM - 1) < (0 + 10) and
(item.CONFIGID = 0 or
item.CONFIGID is null and exists (SELECT config.CONFIGID FROM CONFIGURATION config WHERE config.CONFIGID = 0 and config.ISDEFAULT = 1));
This request returned me zero results.
I changed it to:
SELECT item.NAME,
item.ITEMID,
item.CONFIGID,
ROWNUM
FROM
ITEMS item
WHERE
(ROWNUM - 1) >= 0 and
(ROWNUM - 1) < (0 + 10) and
(item.CONFIGID = 0 or
item.CONFIGID is null and exists (SELECT config.CONFIGID FROM CONFIGURATION config WHERE config.CONFIGID = 0 and config.ISDEFAULT = 1));
And it worked! Adding the ROWNUM in the SELECT statement fixed the issue.
Then I tried:
SELECT *
FROM
ITEMS item
WHERE
ROWNUM >= (0 + 1) and
ROWNUM < (0 + 1 + 10) and
(item.CONFIGID = 0 or
item.CONFIGID is null and exists (SELECT config.CONFIGID FROM CONFIGURATION config WHERE config.CONFIGID = 0 and config.ISDEFAULT = 1));
I wrote back the SELECT * statement and moved the - 1 to the other sides of the comparison operators (therefore they became + 1). This works as well.
Can someone explain why my first query does not work and yields zero results whereas the other two work like a charm?
I think there is nothing wrong with ROWNUM.
Can you try to execute:
SELECT *
FROM ITEMS item
WHERE
(ROWNUM - 1) >= 0 and
(ROWNUM - 1) < (0 + 10);
SELECT item.NAME,
item.ITEMID,
item.CONFIGID,
ROWNUM
FROM ITEMS item
WHERE
(ROWNUM - 1) >= 0 and
(ROWNUM - 1) < (0 + 10);
Both should work ok. Which means you have problem with second part of the filter.
The following subquery
(SELECT config.CONFIGID FROM CONFIGURATION config WHERE config.CONFIGID = 0 and config.ISDEFAULT = 1));
is uncorreleated. So it whould always return same result for any record. I think you have to add brackets into condition by item.CONFIGID:
(item.CONFIGID = 0) or
(
item.CONFIGID is null and
exists (SELECT ...)
)
or
(item.CONFIGID = 0 or
item.CONFIGID is null) and
exists (SELECT ...)
I think that is your problem. But not sure without seeing data.

rank over in mysql

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
)