Combine multiple queries into one query - sql

I am trying to group by clientid and m.id. How can I convert these 2 queries into 1 query?
Query 1
select cs.clientid, count(distinct(m.id)) as cp
into #temp
from call_table cs
join mem_table m
on cs.CLIENTID = m.clientid
join activity_table a
on a.memid = m.id
where a.activity = 'abc'
group by cs.clientid, m.id
Query 2
select clientid, sum(cp) from #temp
group by ClientId
Update
More specifically, I am looking to write this query without using a temp table.

You could group only by clientid
And since no fields from activity_table are selected, an EXISTS can be used instead.
select cs.clientid, count(distinct m.id) as cp
from call_table cs
join mem_table m on m.clientid = cs.clientid
where exists
(
select 1
from activity_table a
where a.memid = m.id
and a.activity = 'abc'
)
group by cs.clientid

Why wouldn't you just write this as:
with temp as (
select cs.clientid, count(distinct m.id) as cp
from call_table cs join
mem_table m
on cs.CLIENTID = m.clientid join
activity_table a
on a.memid = m.id
where a.activity = 'abc'
group by cs.clientid, m.id
)
select clientid, sum(cp)
from temp
group by ClientId;
I can't figure out what the logic should really be, but this seems like the simplest way to combine the queries.
I would speculate that you simply want this query:
select cs.clientid, count(distinct m.id) as cp
from call_table cs join
mem_table m
on cs.CLIENTID = m.clientid join
activity_table a
on a.memid = m.id
where a.activity = 'abc'
group by cs.clientid;
That is, remove m.id from the group by. And this can in turn be simplified to:
select m.clientid, count(distinct m.id) as cp
from mem_table m join
activity_table a
on a.memid = m.id
where a.activity = 'abc'
group by cs.clientid;
Assuming that m.id is unique and non-NULL, this can be further simplified to:
select m.clientid, count(*) as cp
from mem_table m join
activity_table a
on a.memid = m.id
where a.activity = 'abc'
group by cs.clientid;

Related

Counting all records from inner-join

I have 4 tables that has aantal ( count ) and each tables shows normal numbers or numbers with - before (example: -20) now I need to count all that records. but I don't know how I can fix that.
Sorry I am a noob in sql.
this is my code
The problem that i facing to is tha all records from the different tables that has column aantal not counting in total.
example:
CSSDKMagento_10_Plankvoorraad returns 10
CSSDKMagento_20_GeenAllocatieWelFiat returns -3 and -2
CSSDKMagento_30_AllocatieVoorraad returns 5
CSSDKMagento_50_AllocatieBestellingBinnen returns -1 and -1
That means that i get on return from Voorraad is 8.
I tried count(*) but that is not the solution. with best way I can do it?
SELECT
i.ItemCode,
g.warehouse,
SUM(g.aantal) AS Voorraad,
MAX(CASE
WHEN g.transtype = 'N' THEN g.sysmodified
ELSE NULL
END) AS LastDate
FROM dbo.CSSDKMagento_10_Plankvoorraad AS g
INNER JOIN dbo.Items AS i
ON (g.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_20_GeenAllocatieWelFiat AS a
ON (a.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_30_AllocatieVoorraad AS v
ON (v.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_50_AllocatieBestellingBinnen AS b
ON (b.artcode = i.ItemCode)
WHERE
i.itemcode = 'TEST'
GROUP BY i.itemcode,
g.warehouse;
Try this
SELECT
i.ItemCode,
g.warehouse,
SUM(g.aantal)+SUM(a.aantal)+SUM(v.aantal)+SUM(b.aantal) AS Voorraad,
MAX(CASE
WHEN g.transtype = 'N' THEN g.sysmodified
ELSE NULL
END) AS LastDate
FROM dbo.CSSDKMagento_10_Plankvoorraad AS g
INNER JOIN dbo.Items AS i
ON (g.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_20_GeenAllocatieWelFiat AS a
ON (a.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_30_AllocatieVoorraad AS v
ON (v.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_50_AllocatieBestellingBinnen AS b
ON (b.artcode = i.ItemCode)
WHERE
i.itemcode = 'TEST'
GROUP BY i.itemcode,
g.warehouse;
Edited:
SELECT SUM(Voorraad) FROM (
SELECT
i.ItemCode,
g.warehouse,
g.aantal AS Voorraad,
MAX(CASE
WHEN g.transtype = 'N' THEN g.sysmodified
ELSE NULL
END) AS LastDate
FROM dbo.CSSDKMagento_10_Plankvoorraad AS g
INNER JOIN dbo.Items AS i
ON (g.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_20_GeenAllocatieWelFiat AS a
ON (a.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_30_AllocatieVoorraad AS v
ON (v.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_50_AllocatieBestellingBinnen AS b
ON (b.artcode = i.ItemCode)
WHERE
i.itemcode = 'TEST' enter code here
GROUP BY i.itemcode,
g.warehouse
)src
Looks like following would work:
WITH itemCodesScope AS
(
SELECT 'TEST' as target_ItemCode
),
aggregated_CSSDKMagento_10_Plankvoorraad AS
(
SELECT g.artcode,
g.warehouse,
COUNT(g.aantal) as count_aantal,
SUM(g.aantal) as sum_aantal,
MAX(CASE
WHEN g.transtype = 'N' THEN g.sysmodified
ELSE NULL
END) AS LastDate
FROM dbo.CSSDKMagento_10_Plankvoorraad AS g
JOIN itemCodesScope ON itemCodesScope.target_itemCode = g.artcode
GROUP BY
g.artcode,
g.warehouse
),
aggregated_CSSDKMagento_20_GeenAllocatieWelFiat AS
(
SELECT a.artcode ,
COUNT(a.aantal) as count_aantal,
SUM(a.aantal) as sum_aantal
FROM dbo.CSSDKMagento_20_GeenAllocatieWelFiat AS a
JOIN itemCodesScope ON itemCodesScope.target_itemCode = a.artcode
GROUP BY
a.artcode
),
aggregated_CSSDKMagento_30_AllocatieVoorraad AS
(
SELECT v.artcode ,
COUNT(v.aantal) as count_aantal,
SUM(v.aantal) as sum_aantal
FROM dbo.CSSDKMagento_30_AllocatieVoorraad AS v
JOIN itemCodesScope ON itemCodesScope.target_itemCode = v.artcode
GROUP BY
v.artcode
),
aggregated_CSSDKMagento_50_AllocatieBestellingBinnen AS
(
SELECT b.artcode ,
COUNT(b.aantal) as count_aantal,
SUM(b.aantal) as sum_aantal
FROM dbo.CSSDKMagento_50_AllocatieBestellingBinnen AS b
JOIN itemCodesScope ON itemCodesScope.target_itemCode = b.artcode
GROUP BY
b.artcode
)
SELECT
g.artcode as ItemCode,
g.warehouse,
g.sum_aantal AS Voorraad,
g.LastDate AS LastDate,
g.sum_aantal + ISNULL(a.sum_aantal, 0) + ISNULL(v.sum_aantal, 0) + ISNULL(b.sum_aantal, 0) as sum_aantal,
g.count_aantal + ISNULL(a.count_aantal, 0) + ISNULL(v.count_aantal, 0) + ISNULL(b.count_aantal, 0) as count_aantal
FROM aggregated_CSSDKMagento_10_Plankvoorraad AS g
INNER JOIN dbo.Items AS i
ON (g.artcode = i.ItemCode)
INNER JOIN itemCodesScope
ON itemCodesScope.target_itemCode = i.ItemCode
LEFT JOIN aggregated_CSSDKMagento_20_GeenAllocatieWelFiat AS a
ON (a.artcode = i.ItemCode)
LEFT JOIN aggregated_CSSDKMagento_30_AllocatieVoorraad AS v
ON (v.artcode = i.ItemCode)
LEFT JOIN aggregated_CSSDKMagento_50_AllocatieBestellingBinnen AS b
ON (b.artcode = i.ItemCode)
Explanation
SQL-joins produce Cartesian Products, which most probably led to unexpected results in the initial query. Here there are 4 'amount'-tables which are connected via Joins with conditions 'ON (b.artcode = i.ItemCode)', so if there any table contains several records per condition output will contain several records per ItemCode.
Let's say there are 9 records in a-table with a.artcode per single i.ItemCode, so there is a one-to-many relation. And let's say there is 1 record in b-table per single i.ItemCode. Output of Join will have 9 a.aantal records, but 9 repeated b.aantal records as well. Given that there is an aggregation (group by) it will effect that SUM(b.aantal) in this Joins-query will produce 9-time more than sum(b.aantal) in standalone query on b-table only.
Cartesian Product could be seen more easily, if run the initial query without aggregation:
SELECT *
FROM dbo.CSSDKMagento_10_Plankvoorraad AS g
INNER JOIN dbo.Items AS i
ON (g.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_20_GeenAllocatieWelFiat AS a
ON (a.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_30_AllocatieVoorraad AS v
ON (v.artcode = i.ItemCode)
INNER JOIN dbo.CSSDKMagento_50_AllocatieBestellingBinnen AS b
ON (b.artcode = i.ItemCode)
WHERE
i.itemcode = 'TEST'
The fixture was: doing group by aggregation before making joins. Most convenient way for this imho is CTE. With CTE I created 4 temporary tables with aggregates per ItemCode, so temporary tables are one-to-one per ItemCode. Then Joins on one-to-one produce just single output row per ItemCode.

rewrite query in orden to avoid some records

I dont know how to rewrite the the query in order to avoid records with ISPRIMARY = 0. In other words the values allowed must be ISPRIMARY = 1 and ISPRIMARY = NULL.
The query is the next:
select
S.assetnum, S.description, S.serialnum,
S.epp_codactfij, S.location, L.description,
S.EPP_NUMCONTRATO, S.PURCHASEPRICE, U.personid, U.isprimary
from maximo.asset S
left join maximo.locations L on S.location=L.location
left join maximo.assetusercust U on S.assetnum=U.assetnum
where
S.siteid ='TI'
order by S.assetnum
Try adding the following line to the WHERE clause:
select
S.assetnum, S.description, S.serialnum, S.epp_codactfij, S.location, L.description, S.EPP_NUMCONTRATO, S.PURCHASEPRICE, U.personid, U.isprimary
from maximo.asset S
left join maximo.locations L on S.location=L.location
left join maximo.assetusercust U on S.assetnum=U.assetnum
where
S.siteid ='TI'
-- add this line
AND (U.isprimary = 1 OR U.isprimary IS NULL)
order by S.assetnum
select
S.assetnum, S.description, S.serialnum, S.epp_codactfij,
S.location, L.description, S.EPP_NUMCONTRATO,
S.PURCHASEPRICE, U.personid, U.isprimary
from maximo.asset S
left join maximo.locations L on S.location=L.location
left join maximo.assetusercust U on S.assetnum=U.assetnum
WHERE S.siteid ='TI' AND (U.isprimary = 1 OR U.isprimary IS NULL)
order by S.assetnum;
or:
select
S.assetnum, S.description, S.serialnum, S.epp_codactfij,
S.location, L.description, S.EPP_NUMCONTRATO,
S.PURCHASEPRICE, U.personid, U.isprimary
from maximo.asset S
left join maximo.locations L on S.location=L.location
left join maximo.assetusercust U on S.assetnum=U.assetnum
WHERE S.siteid ='TI' AND (U.isprimary <> 0 OR U.isprimary IS NULL)
order by S.assetnum;

SQL Server : JOIN query

I'm newbie in SQL Server and I need some help with SQL Server and JOIN method.
My code is:
SELECT TOP 1000
p.value AS userposition,
p2.value AS usercell,
t.id
FROM
[es] t
JOIN
[user] u ON t.user_uid = u.uid
JOIN
[user] su ON u.superior_uid = su.uid
JOIN
[user_params] up ON t.user_uid = up.user_uid
LEFT JOIN
[params] p ON up.param_id = p.id AND p.name_id = 1
JOIN
[user_params] up2 ON t.user_uid = up2.user_uid
LEFT JOIN
[params] p2 ON up2.param_id = p2.id AND p.name_id = 2
but it returns duplicated records. I want them just as many as rows in [es] table. In MySQL I would use GROUP BY t.id, but in SQL Server that method doesn't work.
Thanks in advance.
EDIT (clarification):
Thank you for your replies. Maybe I should describe my tables structure and what I need to display.
Table [ES]
[id],[user_uid],[more_data]
Table [User]
[uid],[superior_uid],[more_data]
Table [UserParams]
[id],[user_uid],[param_id]
Table [Params]
[id],[param_id],[value]
Now what I need is to get all records from [ES] add user data from [User] add his superior data on [User][superior_uid] which is also an [User] record, add [Params] with [Params][name_id] = 1 as value1 AND add [Params] with [Params][name_id] = 2 as value2 ... through [UserParams] if exists.
I think the problem is with JOIN or GROUP BY. [ES] records with users has no [UserParams] are shown only once, but those with [UserParams] are doubled.I tried LEFT OUTER JOIN but it doesn't work. :(
How about
SELECT DISTINCT TOP 1000
p.value AS userposition,
p2.value AS usercell,
t.id
FROM [es] t
JOIN [user] u ON t.user_uid = u.uid
JOIN [user] su ON u.superior_uid = su.uid
JOIN [user_params] up ON t.user_uid = up.user_uid
LEFT JOIN [params] p ON up.param_id = p.id AND p.name_id = 1
JOIN [user_params] up2 ON t.user_uid = up2.user_uid
LEFT JOIN [params] p2 ON up2.param_id = p2.id AND p.name_id = 2
ORDER BY (whichever rows that you want it to be ordered by) ?
all of your columns need to be in the group by, or part of an aggregate function
p.value AS userposition, #group by or agg func
p2.value AS usercell, #group by or agg func
t.id #group by
Wouldnt be certain without knowing what p.value and p2.value actually mean
Not to sure about the joins but I guess you know what you doing, to select distinct row you can use row_number() function as below
SELECT userposition
,usercell
,id
FROM (
SELECT TOP 1000
p.value AS userposition
,p2.value AS usercell
,t.id
,ROW_NUMBER() OVER (PARTITION BY t.user_uid ORDER BY t.user_uid) rn
FROM [es] t
INNER JOIN [user] u ON t.user_uid = u.[uid]
INNER JOIN [user] su ON u.superior_uid = su.[uid]
INNER JOIN [user_params] up ON t.user_uid = up.user_uid
LEFT JOIN [params] p ON up.param_id = p.id AND p.name_id = 1
INNER JOIN [user_params] up2 ON t.user_uid = up2.user_uid
LEFT JOIN [params] p2 ON up2.param_id = p2.id AND p.name_id = 2
) A
WHERE A.rn = 1
You can get rid of the last 2 joins by combining them, use DISTINCT to not get repeated entries, and use ORDER BY to sort it.
SELECT DISTINCT TOP 1000
p.value AS userposition,
p2.value AS usercell,
t.id
FROM [es] t
JOIN [user] u ON t.user_uid = u.uid
JOIN [user] su ON u.superior_uid = su.uid
JOIN [user_params] up ON t.user_uid = up.user_uid
LEFT JOIN [params] p ON up.param_id = p.id AND (p.name_id = 1 OR p.name_id = 2)
ORDER BY t.id

sql group by clause error

This is the error
Msg 8120, Level 16, State 1, Procedure FollowingUpdates, Line 10
Column 'TopicsComplete.TopicCreationDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is after adding these 2 lines, I need to count a separate table rows (the amount of rows not the count of the topicid) and include in result any ideas? thanks
,COUNT(DISTINCT MC.topicid) AS NewMessagesCount
LEFT OUTER JOIN Messages AS MC ON MC.TopicId = T.TopicId AND MC.userid = #id
#id int = null
,#UserGroupId int = 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, T.UserName, M.MessageCreationDate, T.ReadAccessGroupId, T.PostAccessGroupId, U.UserGroupId, U.UserPhoto, T.UserFullName ,M.UserId AS MessageUserId ,MU.UserName AS MessageUserName
,COUNT(DISTINCT MC.topicid) AS NewMessagesCount
FROM TopicsComplete AS T
LEFT OUTER JOIN Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1
LEFT OUTER JOIN Messages AS MC ON MC.TopicId = T.TopicId AND MC.userid = #id
INNER JOIN Users AS U ON U.UserId = T.UserId
LEFT JOIN Users MU ON MU.UserId = M.UserId
WHERE EXISTS
(SELECT * FROM TopicsComplete
LEFT OUTER JOIN Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 INNER JOIN
topicfollows AS TF ON T.TopicId != TF.topicid INNER JOIN
Users AS U ON U.UserId = T.UserId LEFT OUTER JOIN
Users AS MU ON MU.UserId = M.UserId
WHERE (T.UserId = #id)
UNION SELECT * FROM TopicsComplete
LEFT OUTER JOIN Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 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
When you have an aggregation function in the select, SQL Server quite reasonably assumes that you want to do an aggregation. All columns not in aggregation functions should then be in the group by clause.
In your case, you have COUNT(DISTINCT MC.topicid) AS NewMessagesCount in a select expression. All the other columns should be in the group by. There is no group by, but you get the error anyway, because one should be there.
You need to have any column not contained in an aggregate (max, min, count, sum, etc.) in the GROUP BY clause.

sql union with different expressions

I have this sql which doesnt work as both unions have different expressions, how can this be done? thanks (mssql stored procedure) have no idea where to go from here
SELECT
*
FROM
(SELECT
ROW_NUMBER()
OVER
(ORDER BY T.TopicCreationDate 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, T.UserName, M.MessageCreationDate, T.ReadAccessGroupId, T.PostAccessGroupId, U.UserGroupId, U.UserPhoto, T.UserFullName
,M.UserId AS MessageUserId
,MU.UserName AS MessageUserName
FROM TopicsComplete AS T LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 INNER JOIN
Users AS U ON U.UserId = T.UserId
LEFT JOIN Users MU ON MU.UserId = M.UserId
WHERE EXISTS
( SELECT *
FROM TopicsComplete
LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 INNER JOIN
Users AS U ON U.UserId = T.UserId LEFT OUTER JOIN
Users AS MU ON MU.UserId = M.UserId
WHERE (T.UserId = #id)
UNION
SELECT *
FROM TopicsComplete
LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 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
All the columns returned by both sides of the union have to match (the number of columns and their data types, not the actual names/aliases).
First of all, don't specify the returned columns with SELECT *. It's a bad habit that leads to problems, e.g. when you add a new column to one of the tables.
Secondly, if one part of the union doesn't have enough columns, specify some constants to provide values for those columns (adding an alias for clarity), e.g.
SELECT 0 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, T.UserName, M.MessageCreationDate, T.ReadAccessGroupId, T.PostAccessGroupId, U.UserGroupId, U.UserPhoto, T.UserFullName