Find third largest quote ever created for each of the accounts in the EC1 area - sql-server

Can anyone help I'm new to SQL and trying to figure out the below question see image for the table structure;
Question = Select account name, contact last name, case number, quote number, quote date and quote value for the f third-largest quote ever created for each of the accounts in the EC1 area
So far I got;
Select
a.accountname, cc.lastname, c.casenumber,
q.quotenumber, q.quotedate, q.quotevalue
from
TBL_Quote q
Left join
TBL_case c On q.caseid = c.caseid
Left join
tbl_contact cc On c.contactID = cc. contactID
Left join
tbl_account a On a.accountid = cc.accountid
Where
left(a.postcode, 3) like 'EC1'
and for the third:
SELECT TOP 1 value
FROM
(SELECT DISTINCT TOP 3 value
FROM tbl_quote
ORDER BY value DESC) a
ORDER BY value
I can't seem to combine the top 3 and the query is it best to overpartion by ?

I would suggest joins and a row-limiting clause:
select ac.accountName, co.lastName, ca.caseNumber, qu.quoteNumber
from tbl_account ac
inner join tbl_contact co on co.accountId = ac.accountId
inner join tbl_case ca on ca.contactId = co.contactId
inner join tbl_quote qu on qu.caseId = ca.quoteId
where ac.postcode like 'EC1%'
order by len(qu.value) desc
offset 2 rows fetch next 1 row only

Related

SQL How to display people with highest sum

SELECT EMPLOYEE.Fname,EMPLOYEE.Lname,
D.Dnumber,
SUM(WORKS_ON.HOURS) AS SUMHOUR
FROM PROJECT
INNER JOIN DEPARTMENT D ON D.Dnumber = PROJECT.Dnum
INNER JOIN EMPLOYEE ON PROJECT.Dnum= EMPLOYEE.Dno
INNER JOIN WORKS_ON ON WORKS_ON.Pno = PROJECT.Pnumber
GROUP BY EMPLOYEE.Fname,EMPLOYEE.Lname, D.Dnumber
I'm writing a code that lists people with the highest SUMHOUR.
Now, I've found who has the biggest sum, but I can't set condition like max(sum()) for displaying them.
This is my output. In this image, people with Dnumber '5' have highest SUMHOUR '150' and I want to display them. What should I do?
One simple approach uses TOP:
SELECT TOP 1 WITH TIES
e.Fname,
e.Lname,
d.Dnumber,
SUM(w.HOURS) AS SUMHOUR
FROM PROJECT p
INNER JOIN DEPARTMENT d
ON d.Dnumber = p.Dnum
INNER JOIN EMPLOYEE e
ON p.Dnum = e.Dno
INNER JOIN WORKS_ON w
ON w.Pno = p.Pnumber
GROUP BY
e.Fname,
e.Lname,
d.Dnumber
ORDER BY
SUMHOUR DESC;
You have puted Dnumber in group by so it returns highest SUMHOUR in each Dnumber.
So sloution is just remove Dnumber from group by then it return highest SUMHOUR only.

Group the count values

I want to get the count of property and building and building is linked with property. Below is the query I tried:
select
PT.PropertyTypeName,
Count(PropertyID) as ProperyCount,
Isnull((Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID =P.PropertyID), 0) as BuildingsCount
from Property P
join PropertyType PT
on PT.PropertyTypeID = P.PropertyTypeID
left join AssetToFund AF
on AF.AssetID = P.AssetID
left join Fund F
on F.FundID = AF.FundID
left join Asset A
on A.AssetID = P.AssetID
left join Client C
on C.ClientID = F.ClientID
where C.ClientId=10000001
group by PT.PropertyTypeName,P.PropertyID
I expect values group of type
and I want to group the count with out duplicate of property-type name
sry for bad English.
Try to use the SUM() function on this subquery
Returns the sum of all the values, or only the DISTINCT values, in the expression. SUM can be used with numeric columns only. Null values are ignored.
MSDN
SUM(Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID = P.PropertyID)
When you use GROUP BY then it groups data by columns which you've written in GROUP BY statement. You've written :
GROUP BY PT.PropertyTypeName,P.PropertyID`
it means that SQL Engine will get all unique combinations of PropertyTypeName, PropertyID. However, you want just unique PropertyTypeName. So write just this field into GROUP BY statement:
GROUP BY PT.PropertyTypeName
So complete query will look like this:
select
PT.PropertyTypeName,
Count(PropertyID) as ProperyCount,
Isnull((Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID =P.PropertyID), 0) as BuildingsCount
from Property P
join PropertyType PT
on PT.PropertyTypeID = P.PropertyTypeID
left join AssetToFund AF
on AF.AssetID = P.AssetID
left join Fund F
on F.FundID = AF.FundID
left join Asset A
on A.AssetID = P.AssetID
left join Client C
on C.ClientID = F.ClientID
where C.ClientId=10000001
group by PT.PropertyTypeName

IS NULL being ignored

I am trying to run a query in T-SQL to pull back a data set based on a column being null.
This is a simplified version of the code:
SELECT
T1.Col1, T1.Col2,
T1.Col3, T1.Col4
FROM
table1 AS T1
INNER JOIN
table2 AS T2 ON T1.Col2 = T2.Col3
WHERE
T2.Col4 IS NULL
Problem is, the result includes rows where T2.Col4 are NULL and also not NULL, it's like the WHERE clause doesn't exist.
Any ideas would be greatly
UPDATE - full version of code:
SELECT
M.ref
,C.cname
,CL.clname
,C.ccity
,M.productLine
,M.code
,CL.date
,M.dept
,DPT.group
,TK2.tkname
,TK2.tkdept
FROM DB.dbo.manage AS M
OUTER JOIN DB.dbo.ClientManageRelationship AS CMR
ON CMR.RelatedEntityID = M.EntityID
OUTER JOIN DB.dbo.Client AS C
ON C.EntityID = CMR.EntityID
INNER JOIN DB.dbo.ManageCustomerRelationship AS MCR
ON MCR.EntityID = M.EntityID
INNER JOIN DB.dbo.Customer AS CL
ON CL.EntityID = MCR.RelatedID
INNER JOIN DB.dbo.timek AS TK
ON TK.tki = M.tkid
LEFT JOIN (SELECT Group = division, [Department] = newdesc, deptcode FROM DB.csrt.vw_rep_p_l_dept) AS DPT
ON tkdept = DPT.dept
LEFT JOIN (SELECT Name = TK2.tkfirst + ' ' + TK2.tklast, TK2.tki, TK2.dept, TK2.loc FROM DB.dbo.timek as TK2 WITH(NOLOCK)) AS TK2
ON TK2.tki = M.tkid
WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc = 'loc1' OR TK.tkloc = 'loc2'
ORDER BY M.ref
My first answer would be because you're using INNER JOIN. This only returns matches between the 2 tables. TRY FULL OUTER JOIN which will return all values regardless of matches and will include NULLS.
If you were looking to return all rows regardless of matches including NULLS from only one of the tables then use RIGHT or LEFT JOIN.
Say i had 2 tables ('Person' and 'Figure'). Not every person may have entered a figure on any one day. But an example may be i want to return all people regardless of whether they entered a figure or not on a certain day.
My initial approach to this would be a LEFT join because i want to return of all the people(left table) regardless of there being any matches in the figure table(right table)
FROM Person P
LEFT JOIN Figure F
ON P.ID = F.ID
This would produce a result such as
Name Figure
Sam 20
Ben 30
Matt NULL
Simon NULL
Whereas,
An inner join would produce only matching values not including nulls
Name Figure
Sam 20
Ben 30
Left join works the same way as right join but in the opposite direction. This is most likely the problem you were facing. But i hope this helped
I think the problem is in the last part of the where condition.
You should use brackets.
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND (TK.tkloc = 'loc1' OR TK.tkloc = 'loc2')`
or
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc IN ('loc1', 'loc2')`

Extract Specific Data After a aggregation (Or any other solution for the desired result)

I want to select the Total "sales" of a specific "main_category" for the year 2016
(main categories that don't have sales in that year should appear as zero)
I have managed to select the "sales" of a specific "main category" with all the other "main_categories" (that doesn't have any sales) appearing as zero using below query:
SELECT
mc.name,
ISNULL(SUM(s.no_of_units * b.unit_price),0) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
RIGHT JOIN Main_Category mc ON mc.cat_id = c.main_category
--WHERE YEAR(i.trans_date) = 2016
GROUP BY mc.name
--HAVING YEAR(i.trans_date)=2016
but when I try to further segregate it for year 2016 ONLY either by WHERE clause or HAVING clause, it stops showing "main_category" names that have zero sales in the year.
One thing that I can think of is to give the query invoices only from 2016
which I tried to did by doing something like,
Replacing the line:
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
with:
INNER JOIN Invoice i ON i.invoice_ID IN (SELECT invoice_id FROM Invoice in2 WHERE Year(in2.trans_date)=2016)
which did display the categories with zero values but with increased the calculated Sales Amount (from 2069 to something 203151022.75).
I understand this addition is somewhat illogical and disrupts the whole Inner Joins but so far these are the closest thing I can think of or find on the web.
I REPEAT the desired result is: main categories that don't have sales in that year should appear as zero with the year given year/month/date
As Sean and Eli mentioned, RIGHT JOIN is not recommended, you may change it to LEFT JOIN, OR use subquery like this:
SELECT
mc.name,
tCatSales = ISNULL(
(
SELECT
SUM(s.no_of_units * b.unit_price) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
WHERE mc.cat_id = c.main_category
AND YEAR(i.trans_date) = 2016
) , 0)
FROM Main_Category mc
try this:
WHERE ISNULL(YEAR(i.trans_date), 1) = 2016
if you put simple equals conditions on outer join it will eliminate nulls, which give zero-valued rows you desire.
Also note that something like:
WHERE YEAR(i.trans_date) = 2016
is not sargable, see here

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.

Resources