Use having and order by in sql server - sql

I would want to select the elements of the column sanciones.matricula_vehiculo that appear more than once, the next code shows all the elements; but would lack a restricion similiar to > 1
SELECT
vehiculos.marca_vehiculo,
sanciones.matricula_vehiculo,
vehiculos.modelo_vehiculo
FROM vehiculos
INNER JOIN sanciones
ON vehiculos.matricula_vehiculo=sanciones.matricula_vehiculo
ORDER BY vehiculos.marca_vehiculo;

I think this does what you want:
SELECT marca_vehiculo, matricula_vehiculo, modelo_vehiculo
FROM (SELECT v.marca_vehiculo, s.matricula_vehiculo, v.modelo_vehiculo,
COUNT(*) OVER (PARTITION BY s.matricula_vehiculo) as cnt
FROM vehiculos v INNER JOIN
sanciones s
ON v.matricula_vehiculo = s.matricula_vehiculo
) vs
WHERE cnt > 1
ORDER BY marca_vehiculo;

SELECT matricula_vehiculo
FROM vehiculos
INNER JOIN sanciones ON vehiculos.matricula_vehiculo=sanciones.matricula_vehiculo
GROUP BY matricula_vehiculo
HAVING count(*) > 1
ORDER BY vehiculos.marca_vehiculo

This will work too, and you will not have the overhead of a JOIN by using EXISTS:
SELECT
vehiculos.marca_vehiculo,
vehiculos.matricula_vehiculo,
vehiculos.modelo_vehiculo
FROM vehiculos v
WHERE EXISTS ( SELECT *
FROM sanciones s
WHERE s.matricula_vehiculo = v.matricula_vehiculo
HAVING COUNT(*) > 1 )
ORDER BY vehiculos.marca_vehiculo;

Related

multiple joins to same sub query

I need to join to the same table repeatedly but this looks ugly. Any suggestions appreciated. Below is simplified SQL, I have 8 tables in the subquery and it produces many duplicate records of the same date, so I need to find only the newest record for each client. (I don't think DB and/or version should matter, but I am using DB2 11.1 LUW)
select c.client_num, a.eff_date, t.trx_date
from client c
join address a on(a.id = c.addr_id)
join transaction t on(t.addr_id = a.id)
{many other joins}
where {many conditions};
select SQ.*
from [ABOVE_SUBQUERY] SQ
join
(select client_num, max(eff_date) AS newest_date from [ABOVE_SUBQUERY] group by client_num) AA
ON(SQ.client_num = AA.client_num and SQ.eff_date = AA.newest_date)
join
(select client_num, max(trx_date) AS newest_date from [ABOVE_SUBQUERY] group by client_num) TT
ON(SQ.client_num = TT.client_num and SQ.trx_date = TT.newest_date)
I need to fine only the newest record for each client.
Can't you just use row_number()?
select t.*
from (select t.*,
row_number() over (partition by client_num order by eff_date desc, eff_time desc) as seqnum
from <whatever> t
) t
where seqnum = 1;

New SQL user - I'm trying to extract the latest record in my query. Accountant new to SQL

For every AbsenceBalance.AbsenceTypesUID I want to return the latest record AbsenceBalance.BalanceTime for each AbsenceBalance.EmployeeUID
I have tried select max but it only returns the most recent entry for the entire table and not by AbsenceBalance.AbsenceTypesUID or AbsenceBalance.EmployeeUID
This is my query
SELECT TOP (1000)
AbsenceBalance.[UID],
AbsenceBalance.BalanceTime,
AbsenceBalance.AbsenceTypesUID,
AbsenceBalance.Mins,
Employee.FullName,
Employee.FirstName,
Employee.LastName,
AbsenceBalance.EmployeeUID,
absencetypes.LongName
from [RiteqDB].[dbo].[AbsenceBalance]
LEFT JOIN [RiteqDB].[dbo].Employee on AbsenceBalance.EmployeeUID = Employee.UID
LEFT JOIN [RiteqDB].[dbo].AbsenceTypes on absencebalance.AbsenceTypesUID = absencetypes.UID
where AbsenceBalance.[UID] = (select max (AbsenceBalance.[UID]) from [RiteqDB].[dbo].[AbsenceBalance] where AbsenceBalance.AbsenceTypesUID = AbsenceBalance.AbsenceTypesUID)
--where Select Max(v) from (values (AbsenceBalance.BalanceTime)
order by FullName, AbsenceTypesUID
It sounds like you might need a group by link, then either use an inner select in a where (like you have) or use this with an inner join.
SELECT
Max(AbsenceBalance.[UID]),
AbsenceBalance.AbsenceTypesUID,
AbsenceBalance.EmployeeUID,
from [RiteqDB].[dbo].[AbsenceBalance]
GROUP BY AbsenceTypesUID, EmployeeUID
;with cte as (
SELECT TOP (1000) AB.[UID]
,AB.BalanceTime
,AB.AbsenceTypesUID
,AB.Mins
,E.FullName
,E.FirstName
,E.LastName
,AB.EmployeeUID
,AT.LongName
, ROW_NUMBER() OVER(PARTITION BY AB.[UID], AB.EmployeeUID order by AB.BalanceTime DESC) AS RUN
FROM [RiteqDB].[dbo].[AbsenceBalance] AB
LEFT JOIN [RiteqDB].[dbo].Employee E ON AB.EmployeeUID = E.UID
LEFT JOIN [RiteqDB].[dbo].AbsenceTypes AT ON AB.AbsenceTypesUID = AT.UID
)
select * from cte
where RUN = 1
In your where condition your comparing with itself that might be the issue.
select max (AbsenceBalance.[UID]) from [RiteqDB].[dbo].[AbsenceBalance]
where AbsenceBalance.AbsenceTypesUID = AbsenceBalance.AbsenceTypesUID
following is wrong
AbsenceBalance.AbsenceTypesUID = AbsenceBalance.AbsenceTypesUID

Query error IN GROUP BY

I want only one F_LATPRIMI, F_LONPRIMI from any I_ID_NAVE
select I_ID_NAVE ,F_LATPRIMI ,F_LONPRIMI
from(
select
distinct imo,[N_ident_seguenziale]
from
navi
inner join
[ESTERNALIZZAZIONE_FASCICOLINAVE]
ON
[ESTERNALIZZAZIONE_FASCICOLINAVE].[I_ID_NAVE]=navi.[N_ident_seguenziale]
) as tabimo
inner join
posizioni
on
posizioni.[I_ID_NAVE]=tabimo.[N_ident_seguenziale]
where
DATEDIFF(minute, D_TS,GETDATE() )<30
group by I_ID_NAVE
The error is
Msg 8120, Level 16, State 1, Line 3 Column 'posizioni.F_LATPRIMI' is
invalid in the select list because it is not contained in either an
aggregate function or the GROUP BY clause.
I think what you are looking for is not GROUP BY rather ROW_NUMBER() function like
select I_ID_NAVE,
F_LATPRIMI ,
F_LONPRIMI
from (
select
imo,[N_ident_seguenziale], I_ID_NAVE,
F_LATPRIMI ,F_LONPRIMI,
ROW_NUMBER() OVER(PARTITION BY I_ID_NAVE ORDER BY I_ID_NAVE) AS rn
from
navi inner join [ESTERNALIZZAZIONE_FASCICOLINAVE]
ON [ESTERNALIZZAZIONE_FASCICOLINAVE].[I_ID_NAVE] = navi.[N_ident_seguenziale]) tabimo
join posizioni p on p.[I_ID_NAVE] = tabimo.[N_ident_seguenziale]
where DATEDIFF(minute, D_TS,GETDATE() ) < 30
and rn = 1;
One should group by all the columns which is in the select clause...
select I_ID_NAVE ,F_LATPRIMI ,F_LONPRIMI
from(
select
distinct imo,[N_ident_seguenziale]
from
navi
inner join
[ESTERNALIZZAZIONE_FASCICOLINAVE]
ON
[ESTERNALIZZAZIONE_FASCICOLINAVE].[I_ID_NAVE]=navi.[N_ident_seguenziale]
) as tabimo
inner join
posizioni
on
posizioni.[I_ID_NAVE]=tabimo.[N_ident_seguenziale]
where
DATEDIFF(minute, D_TS,GETDATE() )<30
group by I_ID_NAVE,F_LATPRIMI ,F_LONPRIMI
in MsSql when using an Group By, all other columns need to be in an aggregate function (like MAX(), etc).
So maybe what you want is to delete the last row group by I_ID_NAVE.
What do you really want?
Please explain to us so we can help
If you "want the last F_LATPRIMI and F_LONPRIMI from anyI_ID_NAVE"
use the "Last"-Aggregate-function:
select I_ID_NAVE ,LAST(F_LATPRIMI) ,LAST(F_LONPRIMI)
from(
select
distinct imo,[N_ident_seguenziale]
from
navi
inner join
[ESTERNALIZZAZIONE_FASCICOLINAVE]
ON
[ESTERNALIZZAZIONE_FASCICOLINAVE].[I_ID_NAVE]=navi.[N_ident_seguenziale]
) as tabimo
inner join
posizioni
on
posizioni.[I_ID_NAVE]=tabimo.[N_ident_seguenziale]
where
DATEDIFF(minute, D_TS,GETDATE() )<30
group by I_ID_NAVE

Replace no result

I have a query like this:
SELECT TV.Descrizione as TipoVers,
sum(ImportoVersamento) as ImpTot,
count(*) as N,
month(DataAllibramento) as Mese
FROM PROC_Versamento V
left outer join dbo.PROC_TipoVersamento TV
on V.IDTipoVersamento = TV.IDTipoVersamento
inner join dbo.PROC_PraticaRiscossione PR
on V.IDPraticaRiscossioneAssociata = PR.IDPratica
inner join dbo.DA_Avviso A
on PR.IDDatiAvviso = A.IDAvviso
where DataAllibramento between '2012-09-08' and '2012-09-17' and A.IDFornitura = 4
group by V.IDTipoVersamento,month(DataAllibramento),TV.Descrizione
order by V.IDTipoVersamento,month(DataAllibramento)
This query must always return something. If no result is produced a
0 0 0 0
row must be returned. How can I do this. Use a isnull for every selected field isn't usefull.
Use a derived table with one row and do a outer apply to your other table / query.
Here is a sample with a table variable #T in place of your real table.
declare #T table
(
ID int,
Grp int
)
select isnull(Q.MaxID, 0) as MaxID,
isnull(Q.C, 0) as C
from (select 1) as T(X)
outer apply (
-- Your query goes here
select max(ID) as MaxID,
count(*) as C
from #T
group by Grp
) as Q
order by Q.C -- order by goes to the outer query
That will make sure you have always at least one row in the output.
Something like this using your query.
select isnull(Q.TipoVers, '0') as TipoVers,
isnull(Q.ImpTot, 0) as ImpTot,
isnull(Q.N, 0) as N,
isnull(Q.Mese, 0) as Mese
from (select 1) as T(X)
outer apply (
SELECT TV.Descrizione as TipoVers,
sum(ImportoVersamento) as ImpTot,
count(*) as N,
month(DataAllibramento) as Mese,
V.IDTipoVersamento
FROM PROC_Versamento V
left outer join dbo.PROC_TipoVersamento TV
on V.IDTipoVersamento = TV.IDTipoVersamento
inner join dbo.PROC_PraticaRiscossione PR
on V.IDPraticaRiscossioneAssociata = PR.IDPratica
inner join dbo.DA_Avviso A
on PR.IDDatiAvviso = A.IDAvviso
where DataAllibramento between '2012-09-08' and '2012-09-17' and A.IDFornitura = 4
group by V.IDTipoVersamento,month(DataAllibramento),TV.Descrizione
) as Q
order by Q.IDTipoVersamento, Q.Mese
Use COALESCE. It returns the first non-null value. E.g.
SELECT COALESCE(TV.Desc, 0)...
Will return 0 if TV.DESC is NULL.
You can try:
with dat as (select TV.[Desc] as TipyDesc, sum(Import) as ToImp, count(*) as N, month(Date) as Mounth
from /*DATA SOURCE HERE*/ as TV
group by [Desc], month(Date))
select [TipyDesc], ToImp, N, Mounth from dat
union all
select '0', 0, 0, 0 where (select count (*) from dat)=0
That should do what you want...
If it's ok to include the "0 0 0 0" row in a result set that has data, you can use a union:
SELECT TV.Desc as TipyDesc,
sum(Import) as TotImp,
count(*) as N,
month(Date) as Mounth
...
UNION
SELECT
0,0,0,0
Depending on the database, you may need a FROM for the second SELECT. In Oracle, this would be "FROM DUAL". For MySQL, no FROM is necessary

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