SQL INSERT ISSUE WITH CTE - sql

I have the following query that I am working on. The goal is to insert the [AppID] and randomly selected [ufid] that meet the criteria in the where clause without inserting duplicates. I have researched the TABLESAMPLE and Random() but was unable to figure this out.
For example: #mult_nuf table has 4 records with the AppID = 123456 and Major = 'GEBOX'. The #temp_rUF will have a record in the table with the ufid = 'UF7' and sh_plan = 'GEBOX'.I need to insert the [App_ID] and the [ufid] of another [sh_plan] into a temp table WHERE the [Major] and [sh_plan] are NOT be the same. So far a record for every [ufid] is being inserted with the same [Appid]. I have 45 [ufid} in the table so the temp table has 45 records for the same [AppID]. Should only be 4 records for the [AppID] with 4 random [ufid]..
mult_nuf table
AppID Major
004540036 GEBOX
004540036 GEBOX
004540036 GEBOX
004540036 GEBOX
The #temp_ruf table
ufID sh_Plan
U1 GECCE
U2 REDSG
U5 GFRTY
U7 GEBOX
U8 JKIUTY
Sample Output should look like
App_ID ufID
004540036 U1
004540036 U2
004540036 U5
004540036 U8
Query I am working with
WITH Match_NomineesWithReviewers AS
(
SELECT DISTINCT
[AppID],
RTRIM(Major) AS Major
FROM
#mult_nuf
)
SELECT
m.[AppID],
r.ufid
INTO
#TempNTable
FROM
Match_NWithR m
CROSS APPLY
(SELECT ir.ufid
FROM #temp_rUF ir
WHERE m.Major <> ir.sh_plan) r

Assuming you want to do this on a set of AppID's, I'd use ROW_NUMBER and ORDER BY newid() for random, then limit to the first 4 results, something like this:
WITH Match_NomineesWithReviewers AS
(
SELECT
[AppID],
RTRIM(Major) AS Major
FROM
#mult_nuf
GROUP BY
[AppID],
RTRIM(Major)
)
, rownum_matches AS (
SELECT
m.[AppID],
r.ufid,
ROW_NUMBER() OVER (PARTITION BY m.[AppID] ORDER BY newid()) AS rownum
FROM
Match_NomineesWithReviewers m
JOIN
#temp_rUF t ON t.sh_Plan != m.Major
)
SELECT [AppID], ufid FROM rownum_matches WHERE rownum <= 4
If you need it to match the original number of records, maybe something like this:
WITH Match_NomineesWithReviewers AS
(
SELECT
[AppID],
RTRIM(Major) AS Major,
COUNT(1) AS rowcnt
FROM
#mult_nuf
GROUP BY
[AppID],
RTRIM(Major)
)
, rownum_matches AS (
SELECT
m.[AppID],
r.ufid,
m.rowcnt,
ROW_NUMBER() OVER (PARTITION BY m.[AppID] ORDER BY newid()) AS rownum
FROM
Match_NomineesWithReviewers m
JOIN
#temp_rUF t ON t.sh_Plan != m.Major
)
SELECT [AppID], ufid FROM rownum_matches rm WHERE rownum <= rowcnt

You can try something like this. It should work if the appid's are all the same.
INSERT INTO ATempTable
SELECT TOP (SELECT COUNT(1) FROM mult_nuf) Appid,
ufID
FROM
(SELECT DISTINCT *
FROM mult_nuf
CROSS JOIN temp_ruf
WHERE major <> sh_plan) BaseQuery
ORDER BY NEWID()

Related

How to increment rank when same total marks is there using mysql query?

This is my query:
SELECT
`users`.`id` AS userID,
`user_tests`.`id`,
`users`.`profilePic`,
`users`.`firstName`,
`user_tests`.`userId`,
`user_tests`.`isFirstAttempt`,
`user_tests`.`total_marks`,
FIND_IN_SET(
`user_tests`.`total_marks`,
(
SELECT
GROUP_CONCAT(
DISTINCT `user_tests`.`total_marks`
ORDER BY
CAST(
`user_tests`.`total_marks` AS DECIMAL(5, 3)
)
DESC
)
FROM
`user_tests`
WHERE
`user_tests`.`testSeriesId` = '856' AND `user_tests`.`isFirstAttempt` = '1'
)
) AS rank,
FROM
`user_tests`
LEFT JOIN `users` ON `users`.id = `user_tests`.`userId`
WHERE
`user_tests`.`isFirstAttempt` = '1' AND `user_tests`.`testSeriesId` = '856'
ORDER BY
CAST(
`user_tests`.`total_marks` AS DECIMAL(5, 3)
)
DESC
,
`submissionTimeInMinutes` ASC,
`rank` ASC;
Output:
this is the image
Expected:
Here is the expected output image
I am using MariaDB 5.5.68
I've tried using variables to increment but it's showing me the current row number instead of 1,2,3,4,5... numbers.
Can anybody help here?
Thanks.
You don't appear to need a left join as none of the user names are missing. A simple subquery will give you the the ranking by total_mark but I'm not sure whether you're counting users or something else. A CTE would let you avoid duplicating some of the logic and might possibly even be faster. I don't know if you have that option.
SELECT
u.id AS userID, t.id, u.profilePic, u.firstName,
t.userId, t.isFirstAttempt, t.total_marks,
(
SELECT count(distinct userId) from FROM user_tests t2
WHERE t.isFirstAttempt = 1 AND t.testSeriesId = 856
AND t.total_marks < t2.total_marks
) as num_tests
FROM user_tests t inner join users u ON u.id = t.userId
WHERE t.isFirstAttempt = 1 AND t.testSeriesId = 856
ORDER BY total_marks desc, submissionTimeInMinutes, num_tests desc

Remove multiple rows with same ID

So I've done some looking around and wasn't unable to find quite what I was looking for. I have two tables.
1.) Table where general user information is stored
2.) Where a status is generated and stored.
The problem is, is that there are multiple rows for the same users and querying these results in multiple returns. I can't just merge them because they aren't all the same status. I need just the newest status from that table.
Example of the table:
SELECT DISTINCT
TOP(50) cam.UserID AS PatientID,
mppi.DisplayName AS Surgeon,
ISNULL(sci.IOPStatus, 'N/A') AS Status,
tkstat.TrackerStatusID AS Stat_2
FROM
Main AS cam
INNER JOIN
Providers AS rap
ON cam.VisitID = rap.VisitID
INNER JOIN
ProviderInfo AS mppi
ON rap.UnvUserID = mppi.UnvUserID
LEFT OUTER JOIN
Inop AS sci
ON cam.CwsID = sci.CwsID
LEFT OUTER JOIN
TrackerStatus AS tkstat
ON cam.CwsID = tkstat.CwsID
WHERE
(
cam.Location_ID IN
(
'SURG'
)
)
AND
(
rap.IsAttending = 'Y'
)
AND
(
cam.DateTime BETWEEN CONCAT(CAST(GETDATE() AS DATE), ' 00:00:00') AND CONCAT(CAST(GETDATE() AS DATE), ' 23:59:59')
)
AND
(
cam.Status_StatusID != 'Cancelled'
)
ORDER BY
cam.UserID ASC
So I need to grab only the newest Stat_2 from each ID so they aren't returning multiple rows. Each Stat_2 also has an update time meaning I can sort by the time/date that column is : StatusDateTime
One way to handle this is to create a calculated row_number for the table where you need the newest record.
Easiest way to do that is to change your TKSTAT join to a derived table with the row_number calculation and then add a constraint to your join where the RN =1
SELECT DISTINCT TOP (50)
cam.UserID AS PatientID, mppi.DisplayName AS Surgeon, ISNULL(sci.IOPStatus, 'N/A') AS Status, tkstat.TrackerStatusID AS Stat_2
FROM Main AS cam
INNER JOIN Providers AS rap ON cam.VisitID = rap.VisitID
INNER JOIN ProviderInfo AS mppi ON rap.UnvUserID = mppi.UnvUserID
LEFT OUTER JOIN Inop AS sci ON cam.CwsID = sci.CwsID
LEFT OUTER JOIN (SELECT tk.CwsID, tk.TrackerStatusId, ROW_NUMBER() OVER (PARTITION BY tk.cwsId ORDER BY tk.CreationDate DESC) AS rn FROM TrackerStatus tk)AS tkstat ON cam.CwsID = tkstat.CwsID
AND tkstat.rn = 1
WHERE (cam.Location_ID IN ( 'SURG' )) AND (rap.IsAttending = 'Y')
AND (cam.DateTime BETWEEN CONCAT(CAST(GETDATE() AS DATE), ' 00:00:00') AND CONCAT(CAST(GETDATE() AS DATE), ' 23:59:59'))
AND (cam.Status_StatusID != 'Cancelled')
ORDER BY cam.UserID ASC;
Note you need a way to derive what the "newest" status is; I assume there is a created_date or something; you'll need to enter the correct colum name
ROW_NUMBER() OVER (PARTITION BY tk.cwsId ORDER BY tk.CreationDate DESC) AS rn
SQL Server doesn't offer a FIRST function, but you can reproduce the functionality with ROW_NUMBER() like this:
With Qry1 (
Select <other columns>,
ROW_NUMBER() OVER(
PARTITION BY <group by columns>
ORDER BY <time stamp column*> DESC
) As Seq
From <the rest of your select statement>
)
Select *
From Qry1
Where Seq = 1
* for the "newest" record.

Duplicate rows when joining tables

I am having troubles with a SQL. My problem is that I get alot of duplicate rows but I don't know how to fix it.
I have the following tables:
tblCGG with columns: listId, description
tblCLA with columns: listid, CLADescription
tblHEA with columns: listid, HEADescription
tblACT with columns: listid, ACTDescription
If I run these tables seperatly with listid = '132623' I get the following output:
tblCGG: 1 row
tblCLA: 4 rows
tblHEA: 10 rows
tblACT: 4 rows
I want to join these tables together, but I am getting way to many rows.
I tried this query below, but I get 160 rows:
select distinct cgg.listid, cla.claDescription, hea.heaDescription,
act.actDescription
from tblCGG cgg
left join tblCLA cla on cgg.listid = cla.listid
left join tblHEA hea on cgg.listid = hea.listid
left join tblACT act on cgg.listid = act .listid
where cgg.listid = '132623'
Desired Output
listid claDescription heaDescription actDescription
132623 claTest hea1 act1
132623 clads hea2 act2
132623 cloas hea3 act3
132623 ccaa hea4 act4
132623 null hea5 null
132623 null hea6 null
132623 null hea7 null
132623 null hea8 null
132623 null hea9 null
132623 null hea10 null
I am not sure if desired output really has sense. But if it is what you really, REALLY need then.
select coalesce(t.listid, c.listid, a.listid, h.listid) listid,
cladescription, headescription, actdescription
from tblcgg t
FULL OUTER join (select a.*, row_number() over(partition by listid order by cladescription) seq_no from tblcla a) c on t.listid=c.listid
FULL OUTER join (select a.*, row_number() over(partition by listid order by actdescription) seq_no from tblact a) a on t.listid=a.listid and a.seq_no=c.seq_no
FULL OUTER join (select a.*, row_number() over(partition by listid order by headescription) seq_no from tblhea a) h on h.listid=a.listid and (h.seq_no=c.seq_no or h.seq_no=a.seq_no)
where coalesce(t.listid, c.listid, a.listid, h.listid)=132623
I am a bit upset with this code as performance will be low on bigger datasets but can't quickly find better solutions without writing function.
Few words of code explanation:
row_number() is window function for obtaining sequence number of each description in each table (you can play with "order by" in it for desired ordering)
full outer join is something that shouldn't be used lightly as performance is not a good side of it but you want a rather strange output so it is good for it
coalesce() returns first not null value
You really should think if union all descriptions will not be better for you:
select listid, 'cgg' source,description from tblcgg where listid=132623
UNION ALL
select listid, 'act' source,actdescription from tblact where listid=132623
UNION ALL
select listid, 'head' source,headescription from tblhea where listid=132623
UNION ALL
select listid, 'cla' source,cladescription from tblcla where listid=132623
You want a separate list in each column. This isn't really a SQL'ish thing to do, but you can arrange it. One method uses row_number() and group by:
select listid, max(claDescription) as claDescription,
max(heaDescription) as heaDescription,
max(actDescription) as actDescription
from ((select cla.listid, cla.claDescription, NULL as heaDescription, NULL as actDescription,
row_number() over (partition by cla.listid order by cla.listid) as seqnum
from tblCLA cla
) union all
(select hea.listid, NULL as claDescription, hea.heaDescription, NULL as actDescription,
row_number() over (partition by hea.listid order by hea.listid) as seqnum
from tblHEA hea
) union all
(select act.listid, NULL as claDescription, NULL as heaDescription, act.actDescription,
row_number() over (partition by act.listid order by act.listid) as seqnum
from tblACT act
)
) x
where listid = 132623 -- only use single quotes if this is really a string
group by listid, seqnum;
The following query will give the results you're looking for. It's a slight mod of your original, but depends on knowing that tblHEA has the most rows in it:
WITH ctecla as (select listid, cladescription, rownum as cla_rownum from tblcla),
ctehea as (select listid, headescription, rownum as hea_rownum from tblhea),
cteact as (select listid, actdescription, rownum as act_rownum from tblact)
select cgg.listid,
cla.claDescription,
hea.heaDescription,
act.actDescription
from tblCGG cgg
left join cteHEA hea
on hea.listid = cgg.listid
left join cteCLA cla
on cla.listid = hea.listid AND
cla.cla_rownum = hea.hea_rownum
left join cteACT act
on act.listid = hea.listid AND
act.act_rownum = hea.hea_rownum
where cgg.listid = '132623';
SQLFiddle here

How to improve sql script performance

The following script is very slow when its run.
I have no idea how to improve the performance of the script.
Even with a view takes more than quite a lot minutes.
Any idea please share to me.
SELECT DISTINCT
( id )
FROM ( SELECT DISTINCT
ct.id AS id
FROM [Customer].[dbo].[Contact] ct
LEFT JOIN [Customer].[dbo].[Customer_ids] hnci ON ct.id = hnci.contact_id
WHERE hnci.customer_id IN (
SELECT DISTINCT
( [Customer_ID] )
FROM [Transactions].[dbo].[Transaction_Header]
WHERE actual_transaction_date > '20120218' )
UNION
SELECT DISTINCT
contact_id AS id
FROM [Customer].[dbo].[Restaurant_Attendance]
WHERE ( created > '2012-02-18 00:00:00.000'
OR modified > '2012-02-18 00:00:00.000'
)
AND ( [Fifth_Floor_London] = 1
OR [Fourth_Floor_Leeds] = 1
OR [Second_Floor_Bristol] = 1
)
UNION
SELECT DISTINCT
( ct.id )
FROM [Customer].[dbo].[Contact] ct
INNER JOIN [Customer].[dbo].[Wifinity_Devices] wfd ON ct.wifinity_uniqueID = wfd.[CustomerUniqueID]
AND startconnection > '2012-02-17'
UNION
SELECT DISTINCT
comdt.id AS id
FROM [Customer].[dbo].[Complete_dataset] comdt
LEFT JOIN [Customer].[dbo].[Aggregate_Spend_Counts] agsc ON comdt.id = agsc.contact_id
WHERE agsc.contact_id IS NULL
AND ( opt_out_Mail <> 1
OR opt_out_email <> 1
OR opt_out_SMS <> 1
OR opt_out_Mail IS NULL
OR opt_out_email IS NULL
OR opt_out_SMS IS NULL
)
AND ( address_1 IS NOT NULL
OR email IS NOT NULL
OR mobile IS NOT NULL
)
UNION
SELECT DISTINCT
( contact_id ) AS id
FROM [Customer].[dbo].[VIP_Card_Holders]
WHERE VIP_Card_number IS NOT NULL
) AS tbl
Wow, where to start...
--this distinct does nothing. Union is already distinct
--SELECT DISTINCT
-- ( id )
--FROM (
SELECT DISTINCT [Customer_ID] as ID
FROM [Transactions].[dbo].[Transaction_Header]
where actual_transaction_date > '20120218' )
UNION
SELECT
contact_id AS id
FROM [Customer].[dbo].[Restaurant_Attendance]
-- not sure that you are getting the date range you want. Should these be >=
-- if you want everything that occurred on the 18th or after you want >= '2012-02-18 00:00:00.000'
-- if you want everything that occurred on the 19th or after you want >= '2012-02-19 00:00:00.000'
-- the way you have it now, you will get everything on the 18th unless it happened exactly at midnight
WHERE ( created > '2012-02-18 00:00:00.000'
OR modified > '2012-02-18 00:00:00.000'
)
AND ( [Fifth_Floor_London] = 1
OR [Fourth_Floor_Leeds] = 1
OR [Second_Floor_Bristol] = 1
)
-- all of this does nothing because we already have every id in the contact table from the first query
-- UNION
-- SELECT
-- ( ct.id )
-- FROM [Customer].[dbo].[Contact] ct
-- INNER JOIN [Customer].[dbo].[Wifinity_Devices] wfd ON ct.wifinity_uniqueID = wfd.[CustomerUniqueID]
-- AND startconnection > '2012-02-17'
UNION
-- cleaned this up with isnull function and coalesce
SELECT
comdt.id AS id
FROM [Customer].[dbo].[Complete_dataset] comdt
LEFT JOIN [Customer].[dbo].[Aggregate_Spend_Counts] agsc ON comdt.id = agsc.contact_id
WHERE agsc.contact_id IS NULL
AND ( isnull(opt_out_Mail,0) <> 1
OR isnull(opt_out_email,0) <> 1
OR isnull(opt_out_SMS,0) <> 1
)
AND coalesce(address_1 , email, mobile) IS NOT NULL
UNION
SELECT
( contact_id ) AS id
FROM [Customer].[dbo].[VIP_Card_Holders]
WHERE VIP_Card_number IS NOT NULL
-- ) AS tbl
Where exists is generally faster than in as well.
Or conditions are generally slower as well, use more union statements instead.
And learn to use left joins correctly. If you have a where condition (other than where id is null) on the table on teh right side of a left join, it will convert to an inner join. If this is not what you want, then your code is currently giving you an incorrect result set.
See http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN for an explanation of how to fix.
As stated in a comment optimize one at a time. See which one takes the longest and focus on that one.
union will remove duplicates so you don't need the distinct on the individual queries
On you first I would try this:
The left join is killed by the WHERE hnci.customer_id IN so you might as well have a join.
The sub-query is not efficient as cannot use an index on the IN.
The query optimizer does not know what in ( select .. ) will return so it cannot optimize use of indexes.
SELECT ct.id AS id
FROM [Customer].[dbo].[Contact] ct
JOIN [Customer].[dbo].[Customer_ids] hnci
ON ct.id = hnci.contact_id
JOIN [Transactions].[dbo].[Transaction_Header] th
on hnci.customer_id = th.[Customer_ID]
and th.actual_transaction_date > '20120218'
On that second join the query optimizer has the opportunity of which condition to apply first. Let say [Customer].[dbo].[Customer_ids].[customer_id] and [Transactions].[dbo].[Transaction_Header] each have indexes. The query optimizer has the option to apply that before [Transactions].[dbo].[Transaction_Header].[actual_transaction_date].
If [actual_transaction_date] is not indexed then for sure it would do the other ID join first.
With your in ( select ... ) the query optimizer has no option but to apply the actual_transaction_date > '20120218' first. OK some times query optimizer is smart enough to use an index inside the in outside the in but why make it hard for the query optimizer. I have found the query optimizer make better decisions if you make the decisions easier.
A join on a sub-query has the same problem. You take options away from the query optimizer. Give the query optimizer room to breathe.
try this, temptable should help you:
IF OBJECT_ID('Tempdb..#Temp1') IS NOT NULL
DROP TABLE #Temp1
--Low perfomance because of using "WHERE hnci.customer_id IN ( .... ) " - loop join must be
--and this "where" condition will apply to two tables after left join,
--so result will be same as with two inner joints but with bad perfomance
--SELECT DISTINCT
-- ct.id AS id
--INTO #temp1
--FROM [Customer].[dbo].[Contact] ct
-- LEFT JOIN [Customer].[dbo].[Customer_ids] hnci ON ct.id = hnci.contact_id
--WHERE hnci.customer_id IN (
-- SELECT DISTINCT
-- ( [Customer_ID] )
-- FROM [Transactions].[dbo].[Transaction_Header]
-- WHERE actual_transaction_date > '20120218' )
--------------------------------------------------------------------------------
--this will give the same result but with better perfomance then previouse one
--------------------------------------------------------------------------------
SELECT DISTINCT
ct.id AS id
INTO #temp1
FROM [Customer].[dbo].[Contact] ct
JOIN [Customer].[dbo].[Customer_ids] hnci ON ct.id = hnci.contact_id
JOIN ( SELECT DISTINCT
( [Customer_ID] )
FROM [Transactions].[dbo].[Transaction_Header]
WHERE actual_transaction_date > '20120218'
) T ON hnci.customer_id = T.[Customer_ID]
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
INSERT INTO #temp1
( id
)
SELECT DISTINCT
contact_id AS id
FROM [Customer].[dbo].[Restaurant_Attendance]
WHERE ( created > '2012-02-18 00:00:00.000'
OR modified > '2012-02-18 00:00:00.000'
)
AND ( [Fifth_Floor_London] = 1
OR [Fourth_Floor_Leeds] = 1
OR [Second_Floor_Bristol] = 1
)
INSERT INTO #temp1
( id
)
SELECT DISTINCT
( ct.id )
FROM [Customer].[dbo].[Contact] ct
INNER JOIN [Customer].[dbo].[Wifinity_Devices] wfd ON ct.wifinity_uniqueID = wfd.[CustomerUniqueID]
AND startconnection > '2012-02-17'
INSERT INTO #temp1
( id
)
SELECT DISTINCT
comdt.id AS id
FROM [Customer].[dbo].[Complete_dataset] comdt
LEFT JOIN [Customer].[dbo].[Aggregate_Spend_Counts] agsc ON comdt.id = agsc.contact_id
WHERE agsc.contact_id IS NULL
AND ( opt_out_Mail <> 1
OR opt_out_email <> 1
OR opt_out_SMS <> 1
OR opt_out_Mail IS NULL
OR opt_out_email IS NULL
OR opt_out_SMS IS NULL
)
AND ( address_1 IS NOT NULL
OR email IS NOT NULL
OR mobile IS NOT NULL
)
INSERT INTO #temp1
( id
)
SELECT DISTINCT
( contact_id ) AS id
FROM [Customer].[dbo].[VIP_Card_Holders]
WHERE VIP_Card_number IS NOT NULL
SELECT DISTINCT
id
FROM #temp1 AS T

Return top 3 rows per group

When I made this select it shows as result all “rut” with it phone numbers, my problem
is that each “rut” has almost 10 phone numbers, and I need just 3 phone numbers for
each “rut”, I tryied using TOP, but just shows the first 3 rows of all table and not the
first rows by “rut”, how can I use TOP just for the row “rut” and not in the all the
table
Select Distinct
t1.rut_cliente as rut_cliente,
t1.nro_fono as numero
--Into #tmp_numeros
From dat_clientes_sucursales_contactos_telefonos t1,dat_rut_clientes t2
where t1.rut_cliente = t2.rut_cliente
and cod_prioridad = 1
this is what I get with this query:
Rut_cliente Nro_fono
60506000-5 2046840
60506000-5 3507935
60506000-5 4106886
60506000-5 5440000
60506000-5 5445000
81698900-0 2373281
81698900-0 3541342
81698900-0 3541438
81698900-0 3541518
81698900-0 3542101
and this is what I want:
Rut_cliente Nro_fono
60506000-5 2046840
60506000-5 3507935
60506000-5 4106886
81698900-0 2373281
81698900-0 3541342
81698900-0 3541438
thanks in advance.
The question was originally tagged SQL Server 2008, where you can do this using a common table expression:
;WITH x AS
(
SELECT Rut_cliente, Nro_fono, rn = ROW_NUMBER()
OVER (PARTITION BY Rut_cliente ORDER BY Nro_fono)
FROM dbo.dat_clientes_sucursales_contactos_telefonos AS t1
INNER JOIN dbo.dat_rut_clientes AS t2
ON t1.rut_cliente = t2.rut_cliente
WHERE cod_prioridad = 1
)
SELECT Rut_cliente, Nro_fono FROM x
WHERE rn <= 3
ORDER BY Rut_cliente, Nro_fono;
Other comments:
Please don't use table, table syntax. Use proper INNER JOINs. I explain why here.
Please add proper aliases to the inner query, so people know which columns come from t1 and which columns come from t2.
But now we learn the user is actually using SQL Server 2000. This is how I would do it there, I think, but performance is going to be horrible. I'm not 100% sure this works (because again I'm making guesses about which columns come from which table).
SELECT x.rut_cliente, x.nro_fono, COUNT(*) FROM
(
SELECT t1.rut_cliente, t1.nro_fono
FROM dat_clientes_sucursales_contactos_telefonos AS t1
INNER JOIN dat_rut_clientes AS t2
ON t1.rut_cliente = t2.rut_cliente
WHERE cod_prioridad = 1
) AS x
INNER JOIN dat_clientes_sucursales_contactos_telefonos AS b
ON b.rut_cliente = x.rut_cliente
AND b.nro_fono <= x.nro_fono
GROUP BY x.rut_cliente, x.nro_fono
HAVING COUNT(*) <= 3
ORDER BY x.rut_cliente, x.Nro_fono;
For example with ROW_NUMBER which is a window function and returns a row-number for each partition(similar to group by) determined by the order by.:
WITH CTE AS(
SELECT t1.rut_cliente as rut_cliente, t1.nro_fono as numero,
RN = ROW_NUMBER()OVER(PARTITION BY Rut_cliente ORDER BY Nro_fono)
FROM dbo.dat_clientes_sucursales_contactos_telefonos AS t1
INNER JOIN dbo.dat_rut_clientes AS t2 ON t1.rut_cliente = t2.rut_cliente
WHERE cod_prioridad = 1
)
SELECT rut_cliente as rut_cliente, nro_fono as numero
FROM CTE
WHERE RN <= 3
Try this
;with CTE AS (
select Rut_cliente, Nro_fono , ROW_NUMBER() OVER
(PARTITION BY Rut_cliente ORDER BY Nro_fono) rn
FROM dbo.dat_clientes_sucursales_contactos_telefonos AS a
INNER JOIN dbo.dat_rut_clientes AS b
ON a.rut_cliente = b.rut_cliente
WHERE cod_prioridad = 1
)
SELECT * FROM CTE where rn <=3