ROW_NUMBER() alternative - sql-server-2008

I have a table which contains:
ID ID_TYPE
---------------
1 0
2 1
3 1
Now I want to get the current record number when performing:
SELECT ID
FROM IDTable
WHERE ID_TYPE = 1
I don't want to use ROW_NUMBER() OVER (ORDER BY [ID] desc), because it's very slow when using larger tables.
What are my alternatives ?

Try
select ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as number from IDTable WHERE ID_TYPE = 1

Related

MySQL Query to select from table specific rows

I have a table which looks has the following values:
product_id
custom_id
custom_value
1
10
A
1
9
V
2
10
B
3
3
Q
I am looking for a mysql query to get all values from product_id once and select the row which has custom_id = "10" in case it is available. Nevertheless in case custom_id = 10 is not available for a product_id I would still like to return the product_id but also only once.
So the result I am looking for is
product_id
custom_id
custom_value
1
10
A
2
10
B
3
NULL
NULL
Could please someone direct me in the right direction.
select product_id, custom_id, custom_value from table where custom_id = 10
does of course only return the values for product_id "1" and "2"
You can select the first set of rows, then union by a distinct of all the other product id's
select product_id, custom_id, custom_value from table where custom_id = 10
union
select distinct product_id, NULL as custom_id, NULL as custom_value where custom_id <> 10
You can first generate a ROW_NUMBER to get the first element for each "product_id", then transform to NULL values for which "product_id" does not match your value 10, using the IF function.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY product_id ORDER BY custom_id = 10 DESC) AS rn
FROM tab
)
SELECT product_id,
IF(custom_id=10, custom_id, NULL) AS custom_id,
IF(custom_id=10, custom_value, NULL) AS custom_value
FROM cte
WHERE rn = 1
Check the demo here.

select the rows that have more that X occurrences of the same foreign key and ignore the X most recent (timestamp)

I have a table with a property that is a foreign key and another property that is a timestamp
Table
id
fk
timestamp
1
2
16-02-2022
2
2
01-02-2022
3
2
02-02-2021
4
3
24-05-2020
5
3
11-01-2022
6
3
16-09-2021
7
3
01-01-2022
I want to select the rows that have more that X ocurrences of the same foreign key and i want to ignore the X most recent(timestamp) elements for each foreign key
So basically with a X of 2 the select would return
id
fk
timestamp
3
2
02-02-2021
6
3
16-09-2021
4
3
24-05-2020
And with a X of 3 the select would return
id
fk
timestamp
4
3
24-05-2020
Edit:
Thanks alot #forpas for the awesome aproach
Solution
SELECT id, fk, timestamp
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY fk) counter,
ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE counter > ? AND rn > ?;
Use COUNT() and ROW_NUMBER() window functions:
SELECT id, fk, timestamp
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY fk) counter,
ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE counter > ? AND rn > ?;
Replace ? with the values that you want.
But, if the same number X is applied for both the number of total rows for each fk and the number of rows to be dismissed, the query can be simplified:
SELECT id, fk, timestamp
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE rn > ?;
See the demo.
SELECT
id, fk, timestamp
FROM
(
SELECT id, fk, timestamp, ROW_NUMBER() OVER(PARTITION BY fk ORDER BY timestamp ASC) AS X,
COUNT(1) OVER(PARTITION BY fk) AS Total
FROM MyTable
) AS S
WHERE A.Total - S.X >= #X

Select the last record in MySQL in WHERE condition

I have a table that store ticket and statue relation
ticketstatus_Id ticket_Id status_Id
===================================
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2 *
6 3 1
7 4 1
8 3 2 *
I want to select rows that last status_Id equal 2 ,Rows are marked in table.
I think I have to use GROUP BY on column ticket_Id but it return with first status_Id.
This problem is a good candidate for ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticket_Id ORDER BY ticketstatus_Id DESC) rn
FROM yourTable
)
SELECT ticketstatus_Id, ticket_Id, status_Id
FROM cte
WHERE rn = 1 AND status_Id = 2;
The above logic finds all latest rows for each ticket_Id, as ordered by the ticketstatus_Id, whose status_Id values also happens to be 2.
All records with status_Id= '2'
Select * from TABLENAME where status_Id = '2'
Last record with status_Id= '2'
Select * from TABLENAME where status_Id = '2' order by ticketstatus_Id desc limit 1
SELECT * from TABLENAME where status_Id = '2' ORDER BY ticketstatus_Id DESC LIMIT 1;
You can do this with group by and a having clause:
select ticket_Id, max(ticketstatus_Id)
from ticketstatuses
group by ticket_id
having max(ticketstatus_Id) = max(case when status_id = 2 then ticketstatus_Id end);
It would be interesting to know if this has better performance than the row_number() version. However, for performance, this is probably best:
select ts.*
from ticketstatuses ts
where ts.ticketstatus_Id = (select max(ts2.ticketstatus_Id)
from ticketstatus ts2
where ts2.ticket_id = ts.ticket_id
) and
ts.status_id = 2;
This can take advantage of an index on (ticket_id, ticketstatus_id).

SQL Create Unique Value Flag

There are lots of questions/answers about selecting unique values in a MySQL query but I haven't seen any on creating a unique value flag.
I have a customer_ID that can appear more than once in a query output. I want to create a new column that flags whether the customer_ID is unique or not (0 or 1).
The output should look something like this:
ID | Customer ID | Unique_Flag
1 | 1234 | 1
2 | 2345 | 1
3 | 2345 | 0
4 | 5678 | 1
Please let me know if anybody needs clarifications.
You seem to want to mark the first occurrence as unique, but not others. So, let's join in the comparison value:
select t.*,
(id = min_id) as is_first_occurrence
from t join
(select customer_id, min(id) as min_id
from t
group by customer_id
) tt
on t.customer_id = tt.customer_id;
For most people, a "unique" flag would mean that the overall count is "1", not that this is merely the first appearance. If that is what you want, then you can use similar logic:
select t.*,
(id = min_id) as is_first_occurrence,
(cnt = 1) as is_unique
from t join
(select customer_id, min(id) as min_id, count(*) as cnt
from t
group by customer_id
) tt
on t.customer_id = tt.customer_id;
And, in MySQL 8+, you would use window functions:
select t.*,
(row_number() over (partition by customer_id order by id) = 1) as is_first_occurrence,
(count(*) over (partition by customer_id) = 1) as is_unique
from t;
You can try below
select id,a.customerid, case when cnt=1 then 1 else 0 end as Unique_Flag
from tablename a
left join
(select customerid, count(*) as cnt from tablename
group by customerid
)b on a.customerid=b.customerid
You can use lead function as given below to get the required output.
SELECT ID, CUSTOMER_ID,
CASE
WHEN CUSTOMER_ID != CUSTOMER_ID_NEXT THEN 1
ELSE 0
END AS UNIQUE_FLAG FROM
(SELECT ID, CUSTOMER_ID,LEAD(CUSTOMER_ID, 1, 0) OVER (ORDER BY CUSTOMER_ID) AS CUSTOMER_ID_NEXT FROM TABLE)T

SQL : select distinct of one column while ignoring other columns

So I have a table like this :
---------
id, keyid
---------
1, 3
1, 5
1, 6
2, 1
2, 1
2, 3
4, 1
I want the output of the query to be
1,3
2,1
4,1
If i use select distinct(id,keyid) from table it applies the distinct on the pair of id,keyid and not just id alone.
select id, min(keyid) from tbl group by id
If you want the min value of KeyId for each Id, then user194076's answer will definitely work.
If you want the first occurring value of KeyId for each Id, you could use:
WITH CTE AS (
SELECT Id, KeyId, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Id) AS RN
FROM tbl
)
SELECT Id, KeyId FROM CTE WHERE RN = 1
I've tested both using STATISTICS IO and STATISTICS TIME and they appear to be the same in terms of performance, so really depends on what your exact needs are.