I am using SQL server 2014. I have two tables Member and MemberPosition. The MemberPostion table records a history of each member in the database. The memberID is the primary key in the member table, and is a foreign key in the MemberPosition table. I need to return the member that has held the most positions.
Here is the query I am using:
Select
M.MemberFName + ' ' + M.MemberLName as Name
from Member M
Join MemberPosition MP
ON MP.MemberID = M.MemberID
Group By M.MemberFName + ' ' + M.MemberLName
Having Count(MP.MemberID) = (Select max(P) from
(Select Count(MP.MemberID) as P From MP))
I am getting an error near the last )
It tells me incorrect syntax near 'End of file'. Expecting AS,ID, or QUOTED_ID.
Can you tell me what I am doing wrong. I have tried following other examples from the forums but I cannot figure this out.
Subqueries in the from clause need an alias. In your case, this is buried deep in the having clause:
Select M.MemberFName + ' ' + M.MemberLName as Name
from Member M Join
MemberPosition MP
ON MP.MemberID = M.MemberID
Group By M.MemberFName + ' ' + M.MemberLName
Having Count(MP.MemberID) = (Select max(P)
from (Select Count(MP.MemberID) as P
From MP
) p
------------------------------------^
);
There are other ways to do what you want but this follows your query.
Here is an alternative:
Select TOP 1 WITH TIES M.MemberFName + ' ' + M.MemberLName as Name
from Member M Join
MemberPosition MP
ON MP.MemberID = M.MemberID
Group By M.MemberFName + ' ' + M.MemberLName
ORDER BY COUNT(*) DESC;
Related
I am writing select statement in SQL Server. I have to add a select query.
select
acct.AccountID,
acct.Username,
acct.LastNm + ', ' + acct.FirstNm as Name ,
acct.Lastlogin,
acct.email as Email,
(select acct2.FirstNm + ' ' + acct2.LastNm as Name from tblUserAccount acct2
join tblReviewers ra2 on acct2.AccountID = ra2.ReviwerID) as Reviewers
from tblUserAccount acct
I need to get more names from a table called tblReviwers. So 1 user from the tblUserAccount table could be associated with multiple reviews.
The tblReviewers only has 3 column AnalystID, ReviewerID, and Date. When I select on the JOIN between TblUserAccount and TblReviewers on a test AccountID = AnalystID, I can get multiple ReviewerIDs, which their firstname and lastname are located in the tblUserAccount. This is the reason why I use a select subquery
When I run the query, I get the following error
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
I am trying to write a VIEW to get a data.
Any help is greatly appreciated.
A query for a column name can only contain a single record result set. If you have an entry with multiple results causes that error.
I think you are missing disclosure of a possible extra component needed in the reviewers table, the who entered it. This will result in a query similar to the following.
The aliases and relations will appear obvious, but need to be confirmed for your actual structure.
select
EnterBy.AccountID,
EnterBy.Username,
EnterBy.LastNm + ', ' + EnterBy.FirstNm as Name ,
EnterBy.Lastlogin,
EnterBy.email as Email,
ReviewBy.FirstNm + ' ' + ReviewBy.LastNm as ReviewerName
from
tblReviewers r
tblUserAccount EnterBy
on r.AccountID = EnterBy.AccountID
tblUserAccount ReviewBy
on r.ReviwerID = ReviewBy.AccountID
REVISION BASED ON ADDITIONAL DATA
Based on providing the analystID on who entered, you should be good with
select
EnterBy.AccountID,
EnterBy.Username,
EnterBy.LastNm + ', ' + EnterBy.FirstNm as Name ,
EnterBy.Lastlogin,
EnterBy.email as Email,
STUFF(( Select
', [' + ReviewBy.LastNm + ', ' + ReviewBy.FirstNm + '] ' AS [text()]
From
tblReviewers r
JOIN tblUserAccount ReviewBy
on r.ReviwerID = ReviewBy.AccountID
where
r.AnaylstID = EnterBy.AccountID
For XML PATH('')), 1, 2, '' ) as AllReviewers
from
tblUserAccount EnterBy
You cannot have a column that contains multiple rows in a single result set, it just doesn't make sense from SQL perspective. Hence the error.
You should JOIN the tblReviewers table instead of subselecting it. That will yield all Reviewers. Then, JOIN again on the tblUserAccount table to get the name of the Reviewer, and you are all set.
SELECT
acct.AccountID,
acct.Username,
acct.LastNm + ', ' + acct.FirstNm as Name ,
acct.Lastlogin,
acct.email as Email,
acct2.LastNm + ', ' + acct2.FirstNm as ReviewerName ,
FROM tblUserAccount acct
JOIN tblReviewers revi
ON on acct.AccountID = revi.ReviewerID
JOIN tblUserAccount acct2
ON on acct2.AccountID = revi.AnalystID
Starting from Sql Server 2017, You can use something like STRING_AGG function, which combines values from multiple rows into a single string.
Then, your Reviewers column in your query might look like this:
(select STRING_AGG(Name, ',') from
(select acct2.FirstNm + ' ' + acct2.LastNm as Name from tblUserAccount acct2
join tblReviewers ra2 on acct2.AccountID = ra2.ReviwerID
where ra2.AnalystID = acct.AccountID)
) as Reviewers
In this case, names(first name + last name) of the reviewers for the current user will be separated by commas.
Subselects in select lists can only be used to return one value.
In your case, use joins
SELECT
a.AccountID,
a.Username,
a.LastNm + ', ' + a.FirstNm as Name ,
a.Lastlogin,
a.email as Email,
b.LastNm + ', ' + b.FirstNm as ReviewerName
FROM
tblUserAccount a
LEFT JOIN tblReviewers r ON a.AccountID = r.AnalystID
INNER JOIN tblUserAccount b ON r.ReviewerID = b.AccountID
I also used a LEFT JOIN to the reviewers table, in case there is no reviewer defined for an analyst.
You will get several rows per analyst, if more than one reviewer is assigned to it. Usually I solve this problem in the front-end by making a report that puts the main data in a group header (the analyst) and the related date (the reviewers) in the detail section of the report.
Starting with SQL Server 2017, you can also use the STRING_AGG function to concatenate the values of string expressions.
SELECT
a.AccountID,
a.Username,
a.LastNm + ', ' + a.FirstNm AS Name ,
a.Lastlogin,
a.email AS Email,
STRING_AGG(
( SELECT b.LastNm + ' ' + b.FirstNm
FROM
tblReviewers
INNER JOIN tblUserAccount b ON r.ReviewerID = b.AccountID
WHERE
r.AnalystID = a.AccountID ),
', ') AS ReviewerName
FROM
tblUserAccount a
This allows you to return more than one reviewer in one field.
I am attempting to create an hourly dispatch report so for the "hourly" part (in SQL Server 2016) i tried to make queries for each hour and join them but i am getting errors that i cannot understand the query is like so:
Select
*
From
(SELECT
PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) as '9 to 10'
from
[order] o
LEFT OUTER JOIN Order_LifeHistory h ON o.pkOrderID = h.fkOrderId
LEFT OUTER JOIN PackageGroups pg ON o.fkPackagingGroupId = pg.PackageCategoryID
Where
datepart(hour, dprocessedon) between 9
and 10
group by
PackageCategory
) as firstset
FULL JOIN (
SELECT
PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) as '9 to 10'
from
[order] o
LEFT OUTER JOIN Order_LifeHistory h ON o.pkOrderID = h.fkOrderId
LEFT OUTER JOIN PackageGroups pg ON o.fkPackagingGroupId = pg.PackageCategoryID
Where
datepart(hour, dprocessedon) between 10
and 11
group by
PackageCategory
)as secondset on firstset.PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) = secondset.PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar)
and I keep getting the following errors:
Invalid column name 'PackageCategory'.
Invalid column name 'UpdatedBy'.
Invalid column name 'PackageCategory'.
Invalid column name 'UpdatedBy'.
I cannot understand this as each query that i am joining works on its own.
am i missing something obvious?
please excuse my work a i'm very new at this and tend towards the Frankenstein method of writing queries (Digging up other peoples bits and pieces attach them together and hope for a metaphorical bolt of lightning)
thank you for reading
Because your firstset and secondset does not contain these columns.
They both contain only a single column called 9 to 10.
your full join's on clause should be firstset.[9 to 10] = secondset.[9 to 10]
Select
*
From
(SELECT
PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) as '9 to 10'
from
[order] o
LEFT OUTER JOIN Order_LifeHistory h ON o.pkOrderID = h.fkOrderId
LEFT OUTER JOIN PackageGroups pg ON o.fkPackagingGroupId = pg.PackageCategoryID
Where
datepart(hour, dprocessedon) between 9
and 10
group by
PackageCategory
) as firstset
FULL JOIN (
SELECT
PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) as '9 to 10'
from
[order] o
LEFT OUTER JOIN Order_LifeHistory h ON o.pkOrderID = h.fkOrderId
LEFT OUTER JOIN PackageGroups pg ON o.fkPackagingGroupId = pg.PackageCategoryID
Where
datepart(hour, dprocessedon) between 10
and 11
group by
PackageCategory
)as secondset on firstset.[9 to 10] = secondset.[9 to 10]
You're not selecting PackageCategory, you're selecting it's value plus other strings as a column named 9 to 10. Read it again thinking about it:
SELECT
PackageCategory + ' Count ' + Cast (Count (UpdatedBy) as varchar) as '9 to 10'
There are no columns named PackageCategory or UpdatedBy in your select.
Learning, be kind.
Right now, this statement is showing the drivers and the vehicle id's they have used for these trips. how do I make this show only which drivers have used more than one vehicle rather than a list of vehicle ID and which driver used it? (does that make sense?):
SELECT DISTINCT s.vehicleID, o.FirstName + ' ' + o.LastName AS Driver
FROM Operators AS o, Runs AS r, Schedules AS s JOIN Trips AS t
ON s.scheduleID = t.scheduleID
WHERE r.BidDate >= '09/01/2004' AND r.BidDate <= '09/30/2004'
SELECT COUNT(DISTINCT s.vehicleID) AS Count, o.FirstName + ' ' + o.LastName AS Driver
FROM Operators AS o
JOIN Runs AS r ON o.ID = r.OperatorID
JOIN Schedules AS s ON r.ScheduleID = s.ScheduleID
WHERE r.BidDate BETWEEN '09/01/2004' AND '09/30/2004'
GROUP BY o.FirstName + ' ' + o.LastName
HAVING COUNT(DISTINCT s.vehicleID) > 1
My best guess not knowing the foreign key field names in your tables
SELECT
o.FirstName + ' ' + o.LastName AS Driver,
COUNT(s.vehicleID) AS VehicleCount
FROM
Operators AS o
JOIN Runs AS r ON o.operatorID = r.operatorID
JOIN Schedules AS s ON r.runsID = s.runsID
WHERE
r.BidDate >= '09/01/2004'
AND r.BidDate <= '09/30/2004'
GROUP BY
o.FirstName + ' ' + o.LastName
HAVING
COUNT(s.vehicleID) > 1
I don't really know what's the purpose of each table , but assuming you have table (map_driver_To_vehicle) with :
driverId , vehicleID
which represents that
driverid 5 took vehicleId 1
driverid 2 took vehicleId 5
etc...
You can do :
select driverId , cnt=count(distinct vehicleID )
from map_driver_To_vehicle
group by driverid
having count(distinct vehicleID ) >1
nb : you said more then one vehicle. So I presume you mean different car and not used more then one - the same car.
Either way you can remove the distinct.
You can use GROUP BY clause:
SELECT o.FirstName + ' ' + o.LastName AS Driver, COUNT(s.vehicleID) NoOfVehicleUsed
FROM Operators AS o, Runs AS r, Schedules AS s JOIN Trips AS t
ON s.scheduleID = t.scheduleID
WHERE r.BidDate >= '09/01/2004' AND r.BidDate <= '09/30/2004'
GROUP BY o.FirstName + ' ' + o.LastName
HAVING COUNT(s.vehicleID) > 1
I have a table with columns UserID, SiteID, SiteViews and another with UserID, First, Last
And I need to display the data as First + Last, Site1Views, Site2Views
There are only 2 site IDs and I need to have the sum of the SiteViews per User.
Currently I have:
select s.UserFirstName + ' ' + s.UserLastName as 'Name',
j1.SiteViews as 'Site1Name',
j2.SiteViews as 'Site2Name'
from (Users s INNER JOIN Usage j on s.UserID = j.UserID)
I don't know how to do this. Any help would be appreciated.
Sounds like you might want to use PIVOT for this? I can't test it, but this should get you going int he right direction?
select s.UserFirstName + ' ' + s.UserLastName as Name,
[Site1Name],
[Site2Name]
FROM
(SELECT s.UserFirstName + ' ' + s.UserLastName,
SiteName,
SiteVisits
from Users s
INNER JOIN Usage j1
on s.UserID = j1.UserID
)
PIVOT (SUM(SiteVisits) FOR SiteName IN ([Site1Name],[Site2Name])) as p
how I understood it
select s.UserFirstName + ' ' + s.UserLastName as Name
,(Select COUNT(*) from SiteViews s1 where s.UserID = s1.UserID /*other condition*/) as SiteView1
,(Select COUNT(*) from SiteViews s2 where s.UserID = s2.UserID /*other condition*/) as SiteView2
from Users s
I'm starting with this query:
SELECT TOP 1 Parties.FirstName + ' ' + Parties.MiddleName + ' ' + Parties.LastName AS Plaintiffs
FROM Jackets INNER JOIN
JacketPartyLinks ON Jackets.Id = JacketPartyLinks.Jacket_JacketPartyLink INNER JOIN
Parties ON Parties.Id = JacketPartyLinks.JacketPartyLink_Party
WHERE (Jackets.Id = #JacketID) AND (JacketPartyLinks.Role = 0)
What I'd like to accomplish is to take a count of what's returned, and if it's one row, do nothing. If it's more than one row, add something like ", et al". Notice that this query returns a single column, and it while it should be able to run standalone, it also needs to work as a subquery.
How can this be done?
EDIT: Add TOP 1
Use top and count..over and then wrap it in an outer query, like so:
select
Plantiffs + case when PlantiffCount > 1 then ', et al' else '' end as Plantiffs
from
(
SELECT TOP 1
Parties.FirstName + ' ' + Parties.MiddleName + ' ' + Parties.LastName as Plantiffs,
count(1) over () as PlantiffCount
FROM
Jackets
INNER JOIN JacketPartyLinks ON
Jackets.Id = JacketPartyLinks.Jacket_JacketPartyLink
INNER JOIN Parties ON
Parties.Id = JacketPartyLinks.JacketPartyLink_Party
WHERE
(Jackets.Id = #JacketID) AND (JacketPartyLinks.Role = 0)
order by Parties.LastName asc
) x
The over () part after count tells it to count all rows and not group by anything. This is why there isn't a group by clause in that query. You can use over with any aggregate function, which is pretty nifty.