How to add another order by at the end with records sorted by field_id, but order should be in the same way they are set in the IN clause 32015102,32015100,32015101,32015105. The numbers can change and can increase or decrease in count.
select * from dba.form_data where form_id = 207873 and field_id in (32015102,32015100, 32015101, 32015105 )
order by sub_id, array_number
An IN clause contains an unordered set of values. IN (1,2,3) and IN (3,2,1) are considered equal.
So you must add some order criteria. In your case you want 32015102 first, 32015100 second, etc. Present the DBMS the values with appropriate sort keys. E.g.:
select *
from dba.form_data fd
join
(
select 32015102 as value, 1 as sortkey
union all
select 32015100 as value, 2 as sortkey
union all
select 32015101 as value, 3 as sortkey
union all
select 32015105 as value, 4 as sortkey
) criteria on criteria.value = fd.field_id
where fd.form_id = 207873
order by criteria.sortkey;
TSQL solution on one of my DBs:
WITH CTE AS
(
SELECT ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) AS a,
* FROM (VALUES (21963), (21961), (27665)) AS X(b)
)
SELECT tpb.AutoId FROM dbo.TPB AS tpb
JOIN CTE ON CTE.b = tpb.AutoId
ORDER BY CTE.a
Step by step:
Row constructor syntax: SELECT * FORM( VALUES (1), (2), (3)) X(a)
Create a table named X with a column a that contains 1, 2,3.
ROW_NUMBER(): I needed row number for final sorting of the array. It needs an over clause so I used dummy OVER(ORDER BY(SELECT NULL)) which is, well, order by nothing.
Encapsulate this in a CTE, then select from your target table and join it with CTE on your desired order then sort it using corresponding row_numbers.
Related
I have a table as follow
ID
ORDERNO
1
123
1
123
2
456
2
456
During every select query done via application using JDBC, only the grouped records based on ORDERNO should be picked.
That means, for example, during first select query only details related to ID = 1, but we cannot specify the ID number in where clause because we do not know how many number of IDs will be there in future. So the query should yield only one set of records; application will delete those records after picking, hence next select query will result in picking other set of records. How to achieve it?
You can use TOP WITH TIES for this
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID;
If you want to select and delete at the same time you could delete using an OUTPUT clause
WITH cte AS (
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID
)
DELETE cte
OUTPUT deleted.*;
As one option you could select on the MIN(ID) like:
SELECT *
FROM yourtable
WHERE ID = (SELECT MIN(ID) FROM yourtable);
You could also use window functions to do this:
SELECT ID, ORDERNO
FROM
(
SELECT ID, ORDERNO
DENSE_RANK() OVER (ORDER BY ID ASC) AS dr
FROM yourtable
)dt
WHERE dr = 1;
order your rows and select top n number of rows that you want :
select top (1) with ties ID, ORDERNO
from tablename
order by ID asc
I have a view select c1,c2,count from table and it will give result below.
I want to fetch the entire row of maximum and minimum count's value and that should return only two rows with max and min count like below.
How to do it?
The quickest way is probably a union:
(
select c1, c2, count
from the_table
order by count
limit 1
)
union all
(
select c1, c2, count
from the_table
order by count desc
limit 1
)
Usually the individual statements in a UNION, don't need parentheses, but as we want an order by on each of them, they are needed.
Another option would be join against a derived table:
select t1.*
from the_table t1
join (
select min(count) as min_count,
max(count) as max_count
from the_table
) mm on t1.count in (mm.min_count, mm.max_count)
But I doubt that this will be faster.
I would recommend window functions:
select *
from (
select t.*,
row_number() over(order by count) rn_asc,
row_number() over(order by count desc) rn_desc
from mytable t
) t
where 1 in (rn_asc, rn_desc)
order by count
This requires scanning the table only once (as opposed to union all or join).
Is there any optimised way in sql sever to optimse this code, I am trying to find 2nd duplicate
WITH CTE AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY id,AN_KEY ORDER BY [ENTITYID]) AS [rn]
FROM [data].[dbo].[TRANSFER]
)
select *
INTO dbo.#UpSingle
from CTE
where RN=2
UPDATE:
As GurV pointed out - this query doesn't solve the problem. It will only give you the items that have exactly two duplicates, but not the row where the second duplicate lies.
I am just going to leave this here from reference purposes.
Original Answer
Why not try something like this from another SO post: Finding duplicate values in a SQL table
SELECT
id, AN_KEY, COUNT(*)
FROM
[data].[dbo].[TRANSFER]
GROUP BY
id, AN_KEY
HAVING
COUNT(*) = 2
I gather from your original SQL that the cols you would want to group by on are :
Id
AN_KEY
Here is another way to get the the second duplicate row (in the order of increasing ENTITYID of course):
select *
from [data].[dbo].[TRANSFER] a
where [ENTITYID] = (
select min([ENTITYID])
from [data].[dbo].[TRANSFER] b
where [ENTITYID] > (
select min([ENTITYID])
from [data].[dbo].[TRANSFER] c
where b.id = c.id
and b.an_key = c.an_key
)
and a.id = b.id
and a.an_key = b.an_key
)
Provided there is an index on id, an_key and ENTITYID columns, performance of both your query and this should be acceptable.
Let me assume that this query does what you want:
WITH CTE AS (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY id, AN_KEY
ORDER BY [ENTITYID]) AS [rn]
FROM [data].[dbo].[TRANSFER] t
)
SELECT *
INTO dbo.#UpSingle
FROM CTE
WHERE RN = 2;
For performance, you want a composite index on [data].[dbo].[TRANSFER](id, AN_KEY, ENTITYID).
I am looking for generating a random number which the generated number is not there on another table.
For Example: If a table called randomNums having the values 10,20,30,40,50.
I like to generate a number apart from the above values.
I tried the following query.
Query
;WITH CTE AS
(
SELECT FLOOR(RAND()*100) AS rn
)
SELECT rn FROM CTE
WHERE rn NOT IN (SELECT num FROM randomNums);
But sometimes this query returns nothing.
Because that time it generates the number which is there in the table randomNums.
How to solve this issue?
Fiddle for reference
Yet another option, I've always liked NEWID() for random ordering, and cross joins create many rows very efficiently:
;with cte AS (SELECT 1 n UNION ALL SELECT 1)
,cte2 AS (SELECT TOP 100 ROW_NUMBER() OVER(ORDER BY a.n) n
FROM cte a,cte b,cte c,cte d, cte e, cte f, cte g)
SELECT TOP 1 n
FROM cte2 a
WHERE NOT EXISTS (SELECT 1
FROM randomNums b
WHERE a.n = b.num)
ORDER BY NEWID()
Demo: SQL Fiddle
If you don't want to use a WHILE loop then you might look into this solution which employs a recursive CTE:
;WITH CTE AS
(
SELECT FLOOR(RAND()*100) AS rn
UNION ALL
SELECT s.rn
FROM (
SELECT rn
FROM CTE
WHERE rn NOT IN (SELECT num FROM randomNums)
) t
CROSS JOIN (SELECT FLOOR(RAND()*100) AS rn) AS s
WHERE t.rn IS NULL
)
SELECT rn
FROM CTE
EDIT:
As stated in comments below the above does not work: If the first generated number (from the CTE anchor member) is a number already present in randomNums, then the CROSS JOIN of the recursive member will return NULL, hence the number from the anchor member will be returned.
Here is a different version, based on the same idea of using a recursive CTE, that works:
DECLARE #maxAttempts INT = 100
;WITH CTE AS
(
SELECT FLOOR(RAND()*100) AS rn,
1 AS i
UNION ALL
SELECT FLOOR(RAND(CHECKSUM(NEWID()))*100) AS rn, i = i + 1
FROM CTE AS c
INNER JOIN randomNums AS r ON c.rn = r.num
WHERE (i = i) AND (i < #maxAttempts)
)
SELECT TOP 1 rn
FROM CTE
ORDER BY i DESC
Here, the anchor member of the CTE firstly generates a random number. If this number is already present in randomNums the INNER JOIN of the recursive member will succeed, hence yet another random number will be generated. Otherwise, the INNER JOIN will fail and the recursion will terminate.
A couple of things more to note:
i variable is used to record the number of attempts made to generate a 'unique' random number.
The value of i is used in the INNER JOIN operation of the recursive member so as to join with the random value of the immediately preceding recursion only.
Since repetitive calls of RAND() with the same seed value return the same results, we have to use CHECKSUM(NEWID()) as the seed of RAND().
#maxAttempts can optionally be used to specify the maximum number of attempts made in order to generate a 'unique' random number.
SQL Fiddle Demo here
Another option could be to create an unique index on num value for table randomNums. Then in your code catch the possible error if duplicated key is generated, and in that case choose another number and re-try.
Query
declare #RandomNums table (Num int);
insert into #RandomNums values (10),(20),(30),(40),(50),(60),(70),(80),(90);
-- Make a table of AvailableNumbers
with N as
(
select n from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(n)
),
AvailableNumbers as
(
select -- top 97 -- limit as you need
row_number() over(order by (select 1)) as Number
from
N n1, N n2 --, N n3, N n4, N n5, N n6 -- multiply as you need
),
-- Find which of AvailableNumbers is Vacant
VacantNumbers as
(
select
OrdinalNumber = row_number() over(order by an.Number) ,
an.Number
from
AvailableNumbers an
left join #RandomNums rn on rn.Num = an.number
where
rn.Num is null
)
-- select rundom VacantNumber by its OrdinalNumber in VacantNumbers
select
Number
from
VacantNumbers
where
OrdinalNumber = floor(rand()*(select count(*) from VacantNumbers) + 1);
Try
declare #n as int
while #n is null and (select COUNT(*) from randomNums) < 100
Begin
;WITH CTE AS
(
SELECT FLOOR(RAND()*100) AS rn
)
SELECT #n = rn FROM CTE
WHERE rn NOT IN (SELECT num FROM randomNums);
End
select #n
It would only be advisable to use this approach, if the number of exclusions is relatively small.
I think it's easier to show you an image:
So, for each fld_call_id, go to the next value, if it's identical. When we get to the last value, I need the value in column fld_menu_id.
Or, to put it in another way, eliminate fld_call_id duplicates and save only the last one.
You can use ROW_NUMBER:
WITH CTE AS(
SELECT RN = ROW_NUMBER() OVER (PARTITION BY fld_call_id ORDER BY fld_id DESC),
fld_menu_id
FROM dbo.TableName
)
SELECT fld_menu_id FROM CTE WHERE RN = 1
You can create a Rank column and only select that row, something along the lines of the following:
;WITH cte AS
(
SELECT
*
,RANK() OVER (PARTITION BY fld_call_id ORDER BY fld_id DESC) Rnk
FROM YourTable
)
SELECT
*
FROM cte
WHERE Rnk=1
So you GROUP BY fld_call_id and ORDER BY fld_id in descending order so that the last value comes first. These are the rows where Rnk=1.
Edit after comments of OP.
SELECT Table.*
FROM Table
INNER JOIN
(
SELECT MAX(fldMenuID) AS fldMenuID,
fldCallID
FROM Table
GROUP BY fldCallID
) maxValues
ON (maxValues.fldMenuID = Table.fldMenuID
AND maxValues.fldCallID= Table.fldCallID)
Hope This works
SELECT A.*
FROM table A
JOIN (SELECT fld_id,
ROW_NUMBER() OVER (PARTITION BY Fld_call_id ORDER BY fld_id DESC) [Row]
FROM table) LU ON A.fld_id = LU.fld_id
WHERE LU.[Row] = 1