I am using T-SQL and aim to use three WITH clauses to collect into my main table query. If I run each WITH query by themselves, I can get the desired results. But when blending it into my main table query, no results show. I reckon my WITH clauses are okay but have played around with my main table query with no desired outcome.
Any help is much appreicated.
WITH n1 AS (SELECT m.name AS n1nom, SUM(y.Column1) AS SomeTotal1
FROM Mees m
INNER JOIN Listy y
ON y.m1=m.name
WHERE Yr=2020
GROUP BY m.name)
,
n2 AS (SELECT m.name AS n2nom, SUM(y.Column1) AS SomeTotal2
FROM Mees m
INNER JOIN Listy y
ON y.m2=m.name
WHERE Yr=2020
GROUP BY m.name)
,
n3 AS (SELECT m.name AS n3nom, SUM(y.Column1) AS SomeTotal3
FROM Mees m
INNER JOIN Listy y
ON y.m3=m.name
WHERE Yr=2020
GROUP BY m.name)
SELECT m.name, SUM(n1.sometotal1 + n2.sometotal2 + n3.sometotal3) AS Cool
FROM Mees M
INNER JOIN n1
ON n1.n1nom=m.name
INNER JOIN n2
ON n2.n2nom=m.name
INNER JOIN n3
ON n3.n3nom=m.name
GROUP BY m.name, n1.sometotal1 + n2.sometotal2 + n3.sometotal3;
If you want the total of y.Column1 when m.name matches any of y.m1, y.m2 and y.m3 then you need only 1 join and aggregation:
SELECT m.name, SUM(y.Column1) AS Total
FROM Mees m
INNER JOIN Listy y
ON m.name IN (y.m1, y.m2, y.m3)
WHERE Yr = 2020
GROUP BY m.name
If you want to add y.Column1 multiple times in case more than 1 of y.m1, y.m2 and y.m3 match m.name then use a CASE expression inside SUM():
SELECT m.name,
SUM(
(
CASE WHEN m.name = y.m1 THEN 1 ELSE 0 END +
CASE WHEN m.name = y.m2 THEN 1 ELSE 0 END +
CASE WHEN m.name = y.m3 THEN 1 ELSE 0 END
) * y.Column1
) AS Total
FROM Mees m
INNER JOIN Listy y
ON m.name IN (y.m1, y.m2, y.m3)
WHERE Yr = 2020
GROUP BY m.name
Related
I need to divide two queries, but I need to save 'group by' categories. With my query I only get values and their cartesian product.
Select m2.regionname, m2.indicatorname CAST( m2.a2Value as float) /
m1.a1Value
from(
select r.name as regionname , ina.name as indicatorname, sum(a.value) as
a1Value
from Region as "r"
left join city_region as "cr" on r.region_id = cr.region_id
left join Office as "o" on cr.city_id = o.city_id
left join Assets as "a" on o.office_id = a.office_id
left join Indicators as "i" on a.indicator_id = i.indicator_id
left join IndicatorNames as "ina" on i.indicator_name_id =
ina.indicator__name_id
where a.month between '01-01-2019' and '31-01-2019'
group by r.name, ina.name
) m1 join (
select r.name as regionname , ina.name as indicatorname, sum(a.value) as
a2Value
from Region as "r"
left join city_region as "cr" on r.region_id = cr.region_id
left join Office as "o" on cr.city_id = o.city_id
left join Assets as "a" on o.office_id = a.office_id
left join Indicators as "i" on a.indicator_id = i.indicator_id
left join IndicatorNames as "ina" on i.indicator_name_id =
ina.indicator__name_id
where a.month between '01-02-2019' and '27-02-2019'
group by r.name, ina.name) m2 on m1.regionname = m2.regionname
I need to get 4 rows and 3 columns, that includes region_name, indicator_name and float value.
But I only cant get table with values
0,0482248520710059
0,0565972222222222
0,0665680473372781
0,078125
0,705627705627706
0,974025974025974
1,01875
1,03550295857988
1,18343195266272
1,21527777777778
1,38888888888889
1,40625
15,1515151515152
17,3160173160173
21,875
25
but that is wrong.
This condition in the ON clause:
on m1.regionname = m2.regionname
will join many unrelated rows.
You must set another condition like:
on m1.regionname = m2.regionname and m1.indicatorname = m2.indicatorname
try Something like this:
select *, case when a1Value=0 then null else cast(a2Value as float) / a1Value end Ratio
from (
select r.name as regionname , ina.name as indicatorname,
sum(case when a.month between '01-01-2019' and '31-01-2019' then a.value else 0 end) as a1Value,
sum(case when a.month between '01-02-2019' and '27-02-2019' then a.value else 0 end) as a2Value
from Region r
left join city_region cr on r.region_id = cr.region_id
left join Office o on cr.city_id = o.city_id
left join Assets a on o.office_id = a.office_id and a.month between '01-01-2019' and '27-02-2019'
left join Indicators i on a.indicator_id = i.indicator_id
left join IndicatorNames ina on i.indicator_name_id = ina.indicator__name_id
group by r.name, ina.name
) tmp
I need to group this by T.TopicID to only receive the last result.
Whatever I try I get errors like the other T. items rant included in group by or aggregate etc
ALTER PROCEDURE [dbo].[SPGetFollowingTopics]
#id int = null
,#UserGroupId int = null
,#lastvisit DateTime = null
AS
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY TopicOrder DESC,
(CASE
WHEN M.MessageCreationDate > T.TopicCreationDate
THEN M.MessageCreationDate
ELSE T.TopicCreationDate
END) DESC) AS RowNumber,
T.TopicId, T.TopicTitle, T.TopicShortName,
T.TopicDescription, T.TopicCreationDate, T.TopicViews,
T.TopicReplies, T.UserId, T.TopicTags, T.TopicIsClose,
T.TopicOrder, T.LastMessageId, U.UserName,
M.MessageCreationDate, T.ReadAccessGroupId,
T.PostAccessGroupId, TF.userid AS Expr1, U.UserGroupId,
U.UserPhoto, U.UserFullName, M.UserId AS MessageUserId,
MU.UserName AS MessageUserName
FROM
Topics AS T
LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId AND M.Active = 1 AND M.MessageCreationDate < #lastvisit
INNER JOIN
topicfollows AS TF ON T.TopicId = TF.topicid
INNER JOIN
Users AS U ON U.UserId = T.UserId
LEFT JOIN
Users MU ON MU.UserId = M.UserId
WHERE
(TF.userid = #id)
) T
It isn't clear what the requirement is (in my view) but I think you are seeking:
"the latest message"
PER TOPIC
for a given user
In this situation ROW_NUMBER() is a good option but I believe you need to PARTITION the ROW_NUMBER as well as ordering it.
SELECT
*
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY TF.userid, T.TopicId
ORDER BY
(CASE
WHEN M.MessageCreationDate > T.TopicCreationDate THEN M.MessageCreationDate
ELSE T.TopicCreationDate
END) DESC) AS ROWNUMBER
, T.TopicId, T.TopicTitle, T.TopicShortName, T.TopicDescription
, T.TopicCreationDate, T.TopicViews, T.TopicReplies, T.UserId
, T.TopicTags, T.TopicIsClose, T.TopicOrder, T.LastMessageId
, U.UserName, M.MessageCreationDate, T.ReadAccessGroupId
, T.PostAccessGroupId, TF.userid AS EXPR1
, U.UserGroupId, U.UserPhoto, U.UserFullName
, M.UserId AS MESSAGEUSERID, MU.UserName AS MESSAGEUSERNAME
FROM Topics AS T
LEFT OUTER JOIN Messages AS M ON M.TopicId = T.TopicId
AND M.Active = 1
AND M.MessageCreationDate < #lastvisit
INNER JOIN topicfollows AS TF ON T.TopicId = TF.topicid
INNER JOIN Users AS U ON U.UserId = T.UserId
LEFT JOIN Users MU ON MU.UserId = M.UserId
WHERE (TF.userid = #id)
) T
WHERE ROWNUMBER = 1
You could change your left join to any outer apply, and add TOP 1:
SELECT ...
FROM
Topics AS T
OUTER APPLY
( SELECT TOP 1 M.MessageCreationDate, M.UserId
FROM Messages AS M
WHERE M.TopicId = T.TopicId
AND M.Active = 1
AND M.MessageCreationDate < #lastvisit
ORDER BY M.MessageCreationDate DESC
) AS m
This allows you to use TOP 1 and still get one row per topicID
Alternatively you can use ROW_NUMBER() OVER(PARTITION BY m.TopicID ORDER BY M.MessageCreationDate DESC)
SELECT ...
FROM
Topics AS T
LEFT OUTER JOIN
( SELECT M.TopicId,
M.MessageCreationDate,
M.UserId,
RowNum = ROW_NUMBER() OVER(PARTITION BY m.TopicID ORDER BY M.MessageCreationDate DESC)
FROM Messages AS M
WHERE M.Active = 1
AND M.MessageCreationDate < #lastvisit
) AS m
ON M.TopicId = T.TopicId
AND m.RowNum = 1
I would test both methods and see which one works best for you.
i have the following MS ACCESS query that i would like it to return results ordered by name and "paged" by "faking" a rownumber
select * from (SELECT *
FROM (SELECT
s.name as SHolderCategory,
c1.id,
c1.fmember,
c1.link,
m.name as category,
c1.name,
c1.address1,
c1.address2,
c1.city,
c1.state,
c1.zip,
(SELECT COUNT(c2.id) FROM orgs AS c2 WHERE c2.id <= c1.id) AS rownumber
FROM
((orgs AS c1 inner join membershipcls m on m.Id = c1.mClassID)
inner join SHolderscategories s on s.Id = c1.SHolderCategoryID
)
where c1.active = 1)
order by c1.name)
WHERE rownumber > 20 AND rownumber <=40
the problem here is that the ordering is done before the where clause which enforces paging.
so it ends up sorting one page at a time, rather than sorting the whole resultset then paging it...so the results are wrong because in page 1 i have names starting with a to g ... then in page 2 it comes back to names starting with c .... and so on
when i try to get the order clause out so that the query executes the paging first...Mr ACCESS is Angry!!! and tells me it is a COMPLEX query !!!!
any workaround for this?
try also this approach:
SELECT * FROM
(
SELECT TOP 20 *
FROM
(
SELECT TOP 40
s.name as SHolderCategory,
c1.id,
c1.fmember,
c1.link,
m.name as category,
c1.name,
c1.address1,
c1.address2,
c1.city,
c1.state,
c1.zip
FROM
orgs AS c1
inner join membershipcls m on m.Id = c1.mClassID
inner join SHolderscategories s on s.Id = c1.SHolderCategoryID
WHERE c1.active = 1
ORDER BY c1.name
) o
ORDER BY o.name DESC
) f ORDER BY f.name
I have two tables, Main and Details - they have a one-to-many relationship, with one row in Main potentially having multiple rows in Details.
I am trying to create a query that returns all the information from Main, plus the whether the associated rows in Details contain one of a set of codes. Of course, since it's a one-to-many, there may be several of those codes present in Details - and I don't want to double count rows. I need to do it a couple of times over, too.
What I kind of want is something like this:
SELECT m.*, CASE WHEN x.ID IS NOT NULL THEN 1 ELSE 0 END AS Codes1, CASE WHEN y.ID IS NOT NULL THEN 1 ELSE 0 END AS Codes2
FROM [Main] m
LEFT JOIN EXISTS(SELECT d.ID FROM [Details] d WHERE m.ID = d.ID AND d.Code IN (<<Codes1>>)) x
LEFT JOIN EXISTS(SELECT d.ID FROM [Details] d WHERE m.ID = d.ID AND d.Code IN (<<Codes2>>)) y
Is there some way to do this? (This seems something that should be obvious and I'm overcomplicating to the nth degree, but I'm genuinely drawing a blank...
Remove the EXISTS from your query and add a DISTINCT
SELECT DISTINCT
m.*,
CASE WHEN x.ID IS NOT NULL THEN 1 ELSE 0 END AS Codes1,
CASE WHEN y.ID IS NOT NULL THEN 1 ELSE 0 END AS Codes2
FROM [Main] m
LEFT JOIN (SELECT d.ID FROM [Details] d WHERE m.ID = d.ID AND d.Code IN (<<Codes1>>)) x
LEFT JOIN (SELECT d.ID FROM [Details] d WHERE m.ID = d.ID AND d.Code IN (<<Codes2>>)) y
I think this will work:
SELECT M.*,
CASE WHEN C1.Codes IS NULL THEN 0 ELSE 1 END as Codes1,
CASE WHEN C2.Codes IS NULL THEN 0 ELSE 1 END as Codes2
FROM Main M
LEFT
JOIN
(
SELECT d.Id,
COUNT(d.Code) as Codes
FROM Details d
WHERE d.Code in (<<Codes1>>)
GROUP
BY d.Id
) C1
ON C1.Id = M.Id
LEFT
JOIN
(
SELECT d.Id,
COUNT(d.Code) as Codes
FROM Details d
WHERE d.Code in (<<Codes2>>)
GROUP
BY d.Id
) C2
ON C2.Id = M.Id
If you don't need the M.* then this might be better:
SELECT M.Id,
SUM(CASE WHEN D1.Id IS NULL THEN 0 ELSE 1 END) AS Codes1Count,
SUM(CASE WHEN D2.Id IS NULL THEN 0 ELSE 1 END) AS Codes2Count
FROM Main M
LEFT
JOIN Details D1
ON D1.Id = M.Id
AND D1.Code in (<<Codes1>>)
LEFT
JOIN Details D2
ON D2.Id = M.Id
AND D2.Code in (<<Codes2>>)
GROUP
BY M.Id
Here's a slim version of code that will get you what you want
SELECT abb1.*, abb2.mycount
FROM Main AS abb1
JOIN (SELECT Main.ID, COUNT(Details.ID) AS mycount
FROM Main
JOIN Details on Details.ID = Main.ID
GROUP BY Main.ID) AS abb2
i need a report from a database where i need the final result like
Number of Male, Number of Female, showing against city and finally against State.
I started off with something like.
SELECT p.StateName, d.CityName,
count(api.Gender) as Gender
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
when i do this
SELECT p.StateName, d.CityName,
count(api.Gender = 'Male) as Male,
count(api.Gender = 'Female) as Female,
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
it give's me error.
incorrect syntax near =.
i also tried with select statement
COUNT(select api.Gender from api where api.Gender ='Male') as Male,
But it is also not working.
...
Any idea?
SELECT
p.StateName, d.CityName,
sum(case when Gender ='Male' then 1 else 0 end ) as Male_count,
sum(case when Gender ='Female' then 1 else 0 end ) as Female_count
FROM
dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by
p.StateName, d.CityName
You could try the PIVOT function if you are using SQL Server 2005 or later:
WITH CTE AS
( SELECT p.StateName,
d.CityName,
api.Gender
FROM dbo.Application_Personal_information as api
INNER JOIN dbo.state as p
ON api.State = p.ID
INNER JOIN dbo.City as d
ON api.City= d.ID
)
SELECT *
FROM CTE
PIVOT
( COUNT(Gender)
FOR Gender IN ([Male], [Female])
) pvt