TOP And DISTINCT in one query - sql-server

How can i use top and distinct in one statement i am using this but not success . I dont know what i am doing wrong .
Below is my statement that i am using but giving me exception.
SELECT TOP 30 * from
(
SELECT DISTINCT
Bill.CLIENTID,Bill.TRANDATE,Bill.TRANTYPE,Bill.DUE,Bill.AMOUNT,Bill.paid,ORDE_.INVDATE ,Bill.TRANDESC,Bill.INVNUM
FROM BILLING Bill LEFT OUTER JOIN ORDE_ ON Orde_.INVNUM = Bill.INVNUM
WHERE Bill.CLIENTID = 1047 )

Missing table alias for the subquery may be the cause of your error. You don't need a subquery, you can use both Distinct and Top together.
Top(n) records depend on the order of the result set. So don't forget to explicitly Order your results.
SELECT DISTINCT TOP(30) Bill.CLIENTID,Bill.TRANDATE,Bill.TRANTYPE,Bill.DUE,Bill.AMOUNT,
Bill.paid,ORDE_.INVDATE ,Bill.TRANDESC,Bill.INVNUM
FROM BILLING Bill LEFT OUTER JOIN ORDE_ ON Orde_.INVNUM = Bill.INVNUM
WHERE Bill.CLIENTID = 1047
ORDER BY ....

It may help
SELECT TOP 30 * from
(
SELECT DISTINCT
Bill.CLIENTID,Bill.TRANDATE,Bill.TRANTYPE,Bill.DUE,Bill.AMOUNT,Bill.paid,ORDE_.INVDATE ,Bill.TRANDESC,Bill.INVNUM
FROM BILLING Bill LEFT OUTER JOIN ORDE_ ON Orde_.INVNUM = Bill.INVNUM
WHERE Bill.CLIENTID = 1047 ) Alias

Related

Need the sum of two columns from subquery

I have here my query and subquery to generate totals for the types I'm looking for in my database but now I need to somehow get the total for the entire columns. I feel like the solution is right in front of me but I cannot figure it out. Any step in the right direction would be greatly appreciated.
SELECT
SUM(b.aGiven) AS given,
SUM(b.aUsed) AS used
FROM UserAccountGroups AS uag
LEFT OUTER JOIN (
SELECT
uac1.UserAccountGroupID AS aGroupID,
SUM(ua.UserAccountUsedAmount) AS aUsed,
0 AS aGiven
FROM UserAccounts AS ua
LEFT OUTER JOIN UserAccountCodes AS uac1 ON ua.UserAccountCode = uac1.UserAccountCode
WHERE uac1.UserAccountCodeCreatedOn between '07-11-2020' and '07-11-2021'
GROUP BY uac1.UserAccountGroupID
UNION
SELECT
uac.UserAccountGroupID AS aGroupID,
0 AS aUsed,
SUM(uac.UserAccountCodeAmount) AS aGiven
FROM UserAccountCodes AS uac
LEFT OUTER JOIN UserAccounts AS ua1 ON uac.UserAccountCode = ua1.UserAccountCode
WHERE uac.UserAccountCodeCreatedOn between '07-11-2010' and '07-11-2021'
GROUP BY uac.UserAccountGroupID
) AS b ON b.aGroupID = uag.UserAccountGroupID
GROUP BY uag.ReportGroup
*** Update ***
I'm sorry if my question was unclear. This is a query I am using to pull the totals for each type of 'ReportGroup' from the db. Now, rather than needing the totals per group, I need the totals per the column. The idea is to pass in date variables in my codebehind to pull from custom dates and now I would like to have a grand total per column at the bottom of my report. I know I don't need to select any data from UserAccountGroups but I'm having trouble re-working the query to get accurate results. A point in the right direction would be very helpful and thank you beforehand.
If you can provide DML and DDL statements this could have tested easily. This will give sum for each aGroupID and grand total for columns aUsed, aGiven.
SELECT *
into #temp_agg_data
FROM
(
SELECT
uac1.UserAccountGroupID AS aGroupID,
SUM(ua.UserAccountUsedAmount) AS aUsed,
0 AS aGiven
FROM UserAccounts AS ua
LEFT OUTER JOIN UserAccountCodes AS uac1 ON ua.UserAccountCode = uac1.UserAccountCode
WHERE uac1.UserAccountCodeCreatedOn between '07-11-2020' and '07-11-2021'
GROUP BY uac1.UserAccountGroupID
UNION ALL
SELECT
uac.UserAccountGroupID AS aGroupID,
0 AS aUsed,
SUM(uac.UserAccountCodeAmount) AS aGiven
FROM UserAccountCodes AS uac
LEFT OUTER JOIN UserAccounts AS ua1 ON uac.UserAccountCode = ua1.UserAccountCode
WHERE uac.UserAccountCodeCreatedOn between '07-11-2010' and '07-11-2021'
GROUP BY uac.UserAccountGroupID
) AS A
--Last select will list down all records with sum group by [aGroupID] and grand total for [aUsed] , [aGiven] as a row below as 'Grand Total'
SELECT
[aGroupID]
,[aUsed]
,[aGiven]
FROM
#temp_agg_data
UNION ALL
SELECT
'Grand Total' AS [aGroupID]
, SUM(aUsed) as [aUsed]
, SUM(aUsed) as [aGiven]
FROM #temp_agg_data
DROP TABLE #temp_agg_data
You need to take out UserAccountGroupID in the select statements in order to get the Sum of all. Right now, you have UserAccountGroupID in the select, so it is summing by UserAccountGroupID. Hope this answers your question.
the reportGroup has not be used in the join with the subqueries so it can not be grouped by in the result query. Add the reportGroup to filter to the subqueries in the union. You don't need a union or union all sql.
declare #UserAccounts as table(UserAcccountGroupID int,UserAccountCode varchar(10),UserAccountUsedAmount money)
declare #UserAccountCodes as table (UserAccountCode varchar(10),UserAccountCodeCreatedOn Date,UserAccountGroupID int,UserAccountCodeAmount money)
declare #UserAccountGroups as table(UserAccountGroupID int,ReportGroup varchar(10));
select
IsNull(UserAccountCodes.aGiven,0) aGiven
,IsNull(UserAccounts.aUsed,0) aUsed
FROM #UserAccountGroups AS uag
OUTER APPLY
(
SELECT
--uac1.UserAccountGroupID AS aGroupID,
SUM(ua.UserAccountUsedAmount) AS aUsed
--0 AS aGiven
FROM #UserAccounts AS ua
LEFT JOIN #UserAccountCodes AS uac1
ON ua.UserAccountCode = uac1.UserAccountCode
WHERE uac1.UserAccountCodeCreatedOn between '07-11-2020' and '07-11-2021'
and uac1.UserAccountGroupID = uag.UserAccountGroupID
) UserAccounts
outer apply
(
SELECT
--uac.UserAccountGroupID AS aGroupID,
--0 AS aUsed,
SUM(uac.UserAccountCodeAmount) AS aGiven
FROM #UserAccountCodes AS uac
LEFT JOIN #UserAccounts AS ua1
ON uac.UserAccountCode = ua1.UserAccountCode
WHERE uac.UserAccountCodeCreatedOn between '07-11-2010' and '07-11-2021'
and uac.UserAccountGroupID = uag.UserAccountGroupID
) UserAccountCodes

Using the results of WITH clause IN where STATEMENT of main query

I am relatively new at SQL so I apologise if this is obvious but I cannot work out how to use the results of the WITH clause query in the where statement of my main query.
My with query pulls the first record for each customer and gives the sale date for that record:
WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT s.*
FROM summary s
WHERE s.rk=1
I need to use the date in the above query as the starting point and pull all records for each customer for their first 12 months i.e. where the sale date is between ed2.saledate AND ed2.saledate+12 months.
My main query is:
SELECT ed.totalamountincvat, ed.saledate, ed.name AS SaleRef,
ed.customer, ed.customername, comp.numberofemployees,
comp.companyuid
FROM exportdocument AS ed INNER JOIN
FilteredAccount AS comp ON ed.customer = comp.accountid
WHERE (ed.statecode = 0) AND
ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
I am sure that I need to add the main query into the WITH clause but I cant work out where. Is anyone able to help please
Does this help?
;WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT ed.totalamountincvat, ed.saledate, ed.name AS SaleRef,
ed.customer, ed.customername, comp.numberofemployees,
comp.companyuid
FROM exportdocument AS ed INNER JOIN
FilteredAccount AS comp ON ed.customer = comp.accountid
OUTER APPLY (SELECT s.* FROM summary s WHERE s.rk=1) ed2
WHERE ed.statecode = 0 AND
ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
and ed.Customer = ed2.Customer
Results of CTE are not cached or stored, so you can't reuse it.
EDIT:
Based upon your requirement that all the records from CTE should be in final result, this is a new query:
;WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT
ed.totalamountincvat,
ed.saledate,
ed.name AS SaleRef,
ed.customer,
ed.customername,
comp.numberofemployees,
comp.companyuid
FROM
summary ed2
left join exportdocument ed
on ed.Customer = ed2.Customer
and ed.statecode = 0
AND ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
INNER JOIN FilteredAccount comp
ON ed.customer = comp.accountid
WHERE
s.rk=1
summary you will be able to use only once. Alternate solution is store summary into temp table and use that as many times as u want.
Something like : Select * into #temp from Summary s where s.rk=1

How to join one select with another when the first one not always returns a value for specific row?

I have a complex query to retrieve some results:
EDITED QUERY (added the UNION ALL):
SELECT t.*
FROM (
SELECT
dbo.Intervencao.INT_Processo, analista,
ETS.ETS_Sigla, ATC.ATC_Sigla, PAT.PAT_Sigla, dbo.Assunto.SNT_Peso,
CASE
WHEN ETS.ETS_Sigla = 'PE' AND (PAT.PAT_Sigla = 'LIB' OR PAT.PAT_Sigla = 'LBR') THEN (0.3*SNT_Peso)
WHEN ETS.ETS_Sigla = 'CD' THEN (0.3*SNT_Peso)*0.3
ELSE SNT_Peso
END AS PESOAREA,
CASE
WHEN a.max_TEA_FimTarefa IS NULL THEN a.max_TEA_InicioTarefa
ELSE a.max_TEA_FimTarefa
END AS DATA_INICIO_TERMINO,
ROW_NUMBER() OVER (PARTITION BY ATC.ATC_Sigla, a.SRV_Id ORDER BY TEA_FimTarefa DESC) AS seqnum
FROM dbo.Tarefa AS t
INNER JOIN (
SELECT
MAX(dbo.TarefaEtapaAreaTecnica.TEA_InicioTarefa) AS max_TEA_InicioTarefa,
MAX (dbo.TarefaEtapaAreaTecnica.TEA_FimTarefa) AS max_TEA_FimTarefa,
dbo.Pessoa.PFJ_Descri AS analista, dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id
FROM dbo.TarefaEtapaAreaTecnica
LEFT JOIN dbo.Tarefa ON dbo.TarefaEtapaAreaTecnica.TRF_Id = dbo.Tarefa.TRF_Id
LEFT JOIN dbo.AreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.AreaTecnica.ATC_Id
LEFT JOIN dbo.ServicoAreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.ServicoAreaTecnica.ATC_Id
AND dbo.Tarefa.SRV_Id = dbo.ServicoAreaTecnica.SRV_Id
INNER JOIN dbo.Pessoa ON dbo.Pessoa.PFJ_Id = dbo.ServicoAreaTecnica.PFJ_Id_Analista
GROUP BY dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id, dbo.Pessoa.PFJ_Descri
) AS a ON t.SRV_Id = a.SRV_Id
INNER JOIN dbo.TarefaEtapaAreaTecnica AS TarefaEtapaAreaTecnica_1 ON
t.TRF_Id = TarefaEtapaAreaTecnica_1.TRF_Id
AND a.ATC_Id = TarefaEtapaAreaTecnica_1.ATC_Id
AND a.max_TEA_InicioTarefa = TarefaEtapaAreaTecnica_1.TEA_InicioTarefa
LEFT JOIN AreaTecnica ATC ON TarefaEtapaAreaTecnica_1.ATC_Id = ATC.ATC_Id
LEFT JOIN Etapa ETS ON TarefaEtapaAreaTecnica_1.ETS_Id = ETS.ETS_Id
LEFT JOIN ParecerTipo PAT ON TarefaEtapaAreaTecnica_1.PAT_Id = PAT.PAT_Id
LEFT OUTER JOIN dbo.Servico ON a.SRV_Id = dbo.Servico.SRV_Id
INNER JOIN dbo.Intervencao ON dbo.Servico.INT_Id = dbo.Intervencao.INT_Id
LEFT JOIN dbo.Assunto ON dbo.Servico.SNT_Id = dbo.Assunto.SNT_Id
) t
The result is following:
It works good, the problem is that I was asked that if when a row is not present on this query, it must contain values from another table (ServicoAreaTecnica), so I got this query for the other table based on crucial information of the first query. So if I UNION ALL I get this:
Query1 +
UNION ALL
SELECT INN.INT_Processo,
PES.PFJ_Descri,
NULL, --ETS.ETS_Sigla,
ART.ATC_Sigla,
NULL ,--PAT.PAT_Sigla,
ASS.SNT_Peso,
NULL, --PESOAREA
NULL, --DATA_INICIO_TERMINO
NULL --seqnum
FROM dbo.ServicoAreaTecnica AS SAT
INNER JOIN dbo.AreaTecnica AS ART ON ART.ATC_Id = SAT.ATC_Id
INNER JOIN dbo.Servico AS SER ON SER.SRV_Id = SAT.SRV_Id
INNER JOIN dbo.Assunto AS ASS ON ASS.SNT_Id = SER.SNT_Id
INNER JOIN dbo.Intervencao AS INN ON INN.INT_Id = SER.INT_Id
INNER JOIN dbo.Pessoa AS PES ON PES.PFJ_Id = SAT.PFJ_Id_Analista
The result is following:
So what I want to do is to remove row number 1 because row number 2 exists on the first query, I think I got it explained better this time. The result should be only row number 1, row number 2 would appear only if query 1 doesn't retrieve a row for that particular INN.INT_Processo.
Thanks!
Ok, there are two ways to reduce your record set. Given that you've already written the code to produce the table with the extra rows, it might be easiest to just add code to reduce that:
Select * from
(Select *
, Row_Number() over
(partition by IntProcesso, Analista order by ISNULL(seqnum, 0) desc) as RN
from MyResults) a
where RN = 1
This will assign row_number 1 to any rows that came from your first query, or to any rows from the second query that do not have matches in the first query, then filter out extra rows.
You could also use outer joins with isnull or coalesce, as others have suggested. Something like this:
Select ISNULL(a.IntProcesso, b.IntProcesso) as IntProcesso
, ISNULL(a.Analista, b.Analista) as Analista
, ISNULL(a.ETSsigla, b.ETSsigla) as ETSsigla
[repeat for the rest of your columns]
from Table1 a
full outer join Table2 b
on a.IntProcesso = b.IntProcesso and a.Analista = b.Analista
Your code is hard to read, because of the lengthy names of everything (and to be honest, the fact that they're in a language I don't speak also makes it a lot harder).
But how about: replacing your INNER JOINs with LEFT JOINs, adding more LEFT JOINs to draw in the alternative tables, and introducing ISNULL clauses for each variable you want in the results?
If you do something like ... Query1 Right Join Query2 On ... that should get only the rows in Query2 that don't appear in Query 1.

Duplicate record after joining two tables

I am currently having trouble with my query after joining two tables I am getting duplicated records. What i want to do is get the details from table 1 and the payment record from table 2 with same date.. here is my query.
SELECT dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
FROM dbo.tblautoipekonek
LEFT OUTER JOIN dbo.tbladdfunds
ON dbo.tblautoipekonek.date = dbo.tbladdfunds.date
WHERE
( dbo.tblautoipekonek.date = '06/06/2014' )
Hi you can use "Distinct" keyword at after "select" keyword. it will get the single record.
Good to replace dbo.tablename with alias name give to tablename as
select
distinct
auto.IPNo, ... ---here you can add other column of this table.
fund.AddedCTFAmt --same thing done here.
FROM tblAutoIPEkonek auto
LEFT OUTER JOIN dbo.tblAddfunds fund
ON auto.Date = fund.Date --try to add more join condition so filteration done here of data which is fastest/
WHERE (auto.Date = '06/06/2014')
SELECT DISTINCT dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
FROM dbo.tblautoipekonek
LEFT OUTER JOIN dbo.tbladdfunds
ON dbo.tblautoipekonek.date = dbo.tbladdfunds.date
WHERE
( dbo.tblautoipekonek.date = '06/06/2014' )
GROUP BY dbo.tblautoipekonek.ipno,
dbo.tblautoipekonek.awbno,
dbo.tblautoipekonek.ipamount,
dbo.tblautoipekonek.orno,
dbo.tbladdfunds.username,
dbo.tbladdfunds.newctfbal,
dbo.tbladdfunds.addedctfamt,
dbo.tbladdfunds.oldctfbal,
dbo.tbladdfunds.newipbal,
dbo.tbladdfunds.addedipamt,
dbo.tbladdfunds.oldipbal,
dbo.tbladdfunds.date,
dbo.tblautoipekonek.date AS Expr1
Not sure if this will work for you but this is what I would use:
SELECT
p.ipno,
p.awbno,
p.ipamount,
p.orno,
f.username,
f.newctfbal,
f.addedctfamt,
f.oldctfbal,
f.newipbal,
f.addedipamt,
f.oldipbal,
f.date,
p.date Expr1
FROM
dbo.tblautoipekonek p
CROSS APPLY
(
SELECT TOP 1
*
FROM
dbo.tbladdfunds f
WHERE
p.date = f.date
ORDER BY
f.newipbal DESC
) f
This will get you one line from each entry in dbo.tblautoipekonek joined with the matching date entry from dbo.tbladdfunds which has the highest value in newipbal

Join subquery with min

I'm pulling my hair out over a subquery that I'm using to avoid about 100 duplicates (out of about 40k records). The records that are duplicated are showing up because they have 2 dates in h2.datecreated for a valid reason, so I can't just scrub the data.
I'm trying to get only the earliest date to return. The first subquery (that starts with "select distinct address_id", with the MIN) works fine on it's own...no duplicates are returned. So it would seem that the left join (or just plain join...I've tried that too) couldn't possibly see the second h2.datecreated, since it doesn't even show up in the subquery. But when I run the whole query, it's returning 2 values for some ipc.mfgid's, one with the h2.datecreated that I want, and the other one that I don't want.
I know it's got to be something really simple, or something that just isn't possible. It really seems like it should work! This is MSSQL. Thanks!
select distinct ipc.mfgid as IPC, h2.datecreated,
case when ad.Address is null
then ad.buildingname end as Address, cast(trace.name as varchar)
+ '-' + cast(trace.Number as varchar) as ONT,
c.ACCOUNT_Id,
case when h.datecreated is not null then h.datecreated
else h2.datecreated end as Install
from equipmentjoin as ipc
left join historyjoin as h on ipc.id = h.EQUIPMENT_Id
and h.type like 'add'
left join circuitjoin as c on ipc.ADDRESS_Id = c.ADDRESS_Id
and c.GRADE_Code like '%hpna%'
join (select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment)
as h2 on c.address_id = h2.address_id
left join (select car.id, infport.name, carport.number, car.PCIRCUITGROUP_Id
from circuit as car (NOLOCK)
join port as carport (NOLOCK) on car.id = carport.CIRCUIT_Id
and carport.name like 'lead%'
and car.GRADE_Id = 29
join circuit as inf (NOLOCK) on car.CCIRCUITGROUP_Id = inf.PCIRCUITGROUP_Id
join port as infport (NOLOCK) on inf.id = infport.CIRCUIT_Id
and infport.name like '%olt%' )
as trace on c.ccircuitgroup_id = trace.pcircuitgroup_id
join addressjoin as ad (NOLOCK) on ipc.address_id = ad.id
The typical approach to only getting the lowest row is one of the following. You didn't bother to specify what version of SQL Server you're using, what you want to do with ties, and I have little interest to try to work this into your complex query, so I'll show you an abstract simplification for different versions.
SQL Server 2000
SELECT x.grouping_column, x.min_column, x.other_columns ...
FROM dbo.foo AS x
INNER JOIN
(
SELECT grouping_column, min_column = MIN(min_column)
FROM dbo.foo GROUP BY grouping_column
) AS y
ON x.grouping_column = y.grouping_column
AND x.min_column = y.min_column;
SQL Server 2005+
;WITH x AS
(
SELECT grouping_column, min_column, other_columns,
rn = ROW_NUMBER() OVER (ORDER BY min_column)
FROM dbo.foo
)
SELECT grouping_column, min_column, other_columns
FROM x
WHERE rn = 1;
This subqery:
select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment
Probably will return multiple rows because the comment is not guaranteed to be the same.
Try this instead:
CROSS APPLY (
SELECT TOP 1 H2.DateCreated, H2.Comment -- H2.Equipment_id wasn't used
FROM History H2
WHERE
H2.Comment LIKE 'MAC: 5%'
AND C.Address_ID = H2.Address_ID
ORDER BY DateCreated
) H2
Switch that to OUTER APPLY in case you want rows that don't have a matching desired history entry.

Resources