I am using SQL Server 2008 and have written the query:
SELECT
RTRIM(BLDGCODE) AS BLDGCODE,
RTRIM(FLOORCODE) AS FLOORCODE,
SUM(CASE WHEN rtrim(spacetype) LIKE '%fs' THEN 1 ELSE 0 END) AS FLR_SHARED,
SUM(CASE WHEN rtrim(spacetype) LIKE '%bs' THEN 1 ELSE 0 END) AS BLDG_SHARED,
SUM(CASE WHEN rtrim(spacetype) LIKE '%as' AND rtrim(spacetype) NOT IN ('U-TLS-AS', 'U-PARK-AS') THEN 1 ELSE 0 END) AS FLR_ASSIGNABLE,
SUM(CASE WHEN rtrim(spacetype) = 'U-TLS-AS' THEN 1 ELSE 0 END) AS TENANT
FROM FMA0
WHERE
bldgcode in ('us0385', 'us0566')
GROUP BY BLDGCODE, FLOORCODE
ORDER BY BLDGCODE, FLOORCODE
Which returns the result:
BLDGCODE FLOORCODE FLR_SHARED BLDG_SHARED FLR_ASSIGNABLE TENANT
US0385 01-T 0 0 3 1
US0385 02-T 10 0 28 0
US0385 03-T 27 0 404 0
US0385 04-T 83 0 251 0
US0385 05-T 75 0 132 0
US0385 06-T 85 0 191 0
US0385 07-T 73 0 210 0
US0385 08-T 60 1 250 0
US0385 09-T 29 0 270 0
US0385 10-T 22 0 385 0
US0385 11-T 8 23 0 0
US0385 CELL-01 11 5 59 0
US0385 CELL-02 8 3 49 0
US0385 CELL-03 0 3 0 0
US0385 CELL-T 32 0 114 0
US0566 1 0 7 0 3
US0566 2 0 0 0 2
US0566 3 0 0 0 2
US0566 4 0 0 0 2
US0566 LG 4 3 0 4
This is fine but I need an additional column that includes the sum of FLR_ASSIGNABLE for each BLDGCODE, so from the example data above I should see:
BLDGCODE FLOORCODE FLR_SHARED BLDG_SHARED FLR_ASSIGNABLE BLDG_ASSIGNABLE TENANT
US0385 01-T 0 0 3 2346 1
US0385 02-T 10 0 28 2346 0
US0385 03-T 27 0 404 2346 0
US0385 04-T 83 0 251 2346 0
US0385 05-T 75 0 132 2346 0
US0385 06-T 85 0 191 2346 0
US0385 07-T 73 0 210 2346 0
US0385 08-T 60 1 250 2346 0
US0385 09-T 29 0 270 2346 0
US0385 10-T 22 0 385 2346 0
US0385 11-T 8 23 0 2346 0
US0385 CELL-01 11 5 59 2346 0
US0385 CELL-02 8 3 49 2346 0
US0385 CELL-03 0 3 0 2346 0
US0385 CELL-T 32 0 114 2346 0
US0566 1 0 7 0 0 3
US0566 2 0 0 0 0 2
US0566 3 0 0 0 0 2
US0566 4 0 0 0 0 2
US0566 LG 4 3 0 0 4
Also, is it then possible to then filter out the results
Where FLR_SHARED > 0 AND FLR_ASSIGNABLE = 0
OR
Where BLDG_SHARED > 0 AND BLDG_ASSIGNABLE = 0
so I only get
BLDGCODE FLOORCODE FLR_SHARED BLDG_SHARED FLR_ASSIGNABLE BLDG_ASSIGNABLE TENANT
US0385 11-T 8 23 0 2346 0
US0566 1 0 7 0 0 3
US0566 LG 4 3 0 0 4
Hmmm, I think you can do what you want as using a structure like this:
with cte as (
<your query here>
)
select cte.*
from (select cte.*,
sum(bldg_assignable) over (partition by BLDGCODE) as bldg_sum
from cte
) cte
where FLR_SHARED > 0 AND FLR_ASSIGNABLE = 0 and
BLDG_SHARED > 0 AND bldg_sum = 0;
The key idea is to use window functions at one level (in a subquery or CTE). And then filter in an outer query.
I think this is the query you are looking for:
WITH CTE
AS
(SELECT
RTRIM(BLDGCODE) AS BLDGCODE,
RTRIM(FLOORCODE) AS FLOORCODE,
SUM(CASE WHEN rtrim(spacetype) LIKE '%fs' THEN 1 ELSE 0 END) AS FLR_SHARED,
SUM(CASE WHEN rtrim(spacetype) LIKE '%bs' THEN 1 ELSE 0 END) AS BLDG_SHARED,
SUM(CASE WHEN rtrim(spacetype) LIKE '%as' AND rtrim(spacetype) NOT IN ('U-TLS-AS', 'U-PARK-AS') THEN 1 ELSE 0 END) AS FLR_ASSIGNABLE,
SUM(CASE WHEN rtrim(spacetype) = 'U-TLS-AS' THEN 1 ELSE 0 END) AS TENANT
FROM FMA0
WHERE
bldgcode in ('us0385', 'us0566')
GROUP BY BLDGCODE, FLOORCODE
)
SELECT CTE.*, SUM(FLR_ASSIGNABLE) AS BLDG_ASSIGNABLE FROM CTE
where (FLR_SHARED > 0 AND FLR_ASSIGNABLE = 0) or
(BLDG_SHARED > 0 AND SUM(FLR_ASSIGNABLE) = 0)
Related
I know this has been asked a million times before but due to the joins i am finding it hard to correctly write the code required
My SQL is
SELECT DISTINCT
newFvItems.Id, outerFvia.[UserRoleId], outerFvia.[DefaultStatusId], outerFvia.[CanBeAllocated], outerFvia.[CanCreate], outerFvia.[CanUpdate], outerFvia.[CanDelete], outerFvia.[CanSeeDraft], outerFvia.[CanSeeChecking], outerFvia.[CanSeeCompleted], outerFvia.[CanDispute], outerFvia.[CanResolveDispute], outerFvia.[CanAudit], 1, GETUTCDATE(), 393, GETUTCDATE(), 393, 0, outerFvia.[RecycleBinId], outerFvia.[FlowAccessId]
FROM FlowVersionItemAccess outerFvia
JOIN FlowVersionItems outerFvi ON outerFvi.Id = outerFvia.FlowVersionItemId
JOIN FlowVersions outerFv ON outerFv.Id = outerFvi.FlowVersionId
JOIN FlowVersionItems newFvItems ON newFvItems.FlowVersionId = 143
WHERE outerFv.Id = 133
AND outerFvia.Deleted = 0 AND outerFvi.Deleted = 0 AND outerFv.Deleted = 0
My desired output is 21 Rows, i get 27 if i remove DISTINCT i get 63
Sample data:
ID
UserId
val
val
val
val
val
val
val
val
val
val
val
val
DateTime
val
DateTime
val
val
val
val
315
2
2
0
1
1
1
1
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
7
315
6
2
0
1
1
1
1
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
12
315
7
2
0
0
0
0
0
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
16
315
7
2
0
1
1
0
0
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
16
315
18
2
0
0
0
0
0
0
0
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
69
315
18
2
0
1
1
0
0
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
69
Expected data:
ID
UserId
val
val
val
val
val
val
val
val
val
val
val
val
DateTime
val
DateTime
val
val
val
val
315
2
2
0
1
1
1
1
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
7
315
6
2
0
1
1
1
1
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
12
315
7
2
0
1
1
0
0
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
16
315
18
2
0
1
1
0
0
0
1
0
0
0
1
12/12/2022 16:53
393
12/12/2022 16:53
393
0
NULL
69
You can see UserRoleId 7 and 18 are duplicated. I tried to simply group by UserRoleId but i get errors on FlowVersionItems.Id
Msg 8120, Level 16, State 1, Line 44
Column 'FlowVersionItems.Id' is
invalid in the select list because it is not contained in either an
aggregate function or the GROUP BY clause.
Remove DISTINCT, add GROUP BY newFvItems.Id at the very end of query and define aggregating functions (MIN, MAX,...) for all columns you return.
DISTINCT finds all unique combinations of all columns, while you need just one column.
Alternatively, leave only DISTINCT newFvItems.Id in the select part - depends on what you actually need.
There are two solid approaches to this and i thought i would post my solution that i ended up using to hopefully help someone else. The group by solution is good and does provide the correct answer too but this fits an edge case better.
SELECT
newFvItems.Id,
outerFvia.[Id],
outerFvia.[UserRoleId],
outerFvia.[DefaultStatusId],
outerFvia.[CanBeAllocated],
outerFvia.[CanCreate],
outerFvia.[CanUpdate],
outerFvia.[CanDelete],
outerFvia.[CanSeeDraft],
outerFvia.[CanSeeChecking],
outerFvia.[CanSeeCompleted],
outerFvia.[CanDispute], outerFvia.[CanResolveDispute], outerFvia.[CanAudit], 1, GETUTCDATE(), 393, GETUTCDATE(), 393, 0, outerFvia.[RecycleBinId], outerFvia.[FlowAccessId]
FROM FlowVersionItemAccess outerFvia
INNER JOIN FlowVersionItems outerFvi ON outerFvi.Id = outerFvia.FlowVersionItemId
AND outerFvi.Deleted = 0
INNER JOIN FlowVersions outerFv ON outerFv.Id = outerFvi.FlowVersionId
AND outerFv.Deleted = 0
INNER JOIN FlowVersionItems newFvItems ON newFvItems.FlowVersionId = 143
AND newFvItems.Deleted = 0
AND newFvItems.[Order] = outerFvi.[Order]
WHERE outerFvia.Deleted = 0
AND outerFv.Id = 133
Here is the group by solution too.
SELECT
newFvItems.Id,
outerFvia.[UserRoleId],
MAX(outerFvia.[DefaultStatusId]),
MAX(CAST(outerFvia.[CanBeAllocated] As tinyint)),
MAX(CAST(outerFvia.[CanCreate] as tinyint)),
MAX(CAST(outerFvia.[CanUpdate] as tinyint)),
MAX(CAST(outerFvia.[CanDelete] as tinyint)),
MAX(CAST(outerFvia.[CanSeeDraft] as tinyint)),
MAX(CAST(outerFvia.[CanSeeChecking] as tinyint)),
MAX(CAST(outerFvia.[CanSeeCompleted] as tinyint)),
MAX(CAST(outerFvia.[CanDispute] as tinyint))
--, MAX(outerFvia.[CanResolveDispute]), MAX(outerFvia.[CanAudit]), 1, GETUTCDATE(), 393, GETUTCDATE(), 393, 0, MAX(outerFvia.[RecycleBinId]), MAX(outerFvia.[FlowAccessId])
FROM FlowVersionItemAccess outerFvia
JOIN FlowVersionItems outerFvi ON outerFvi.Id = outerFvia.FlowVersionItemId
JOIN FlowVersions outerFv ON outerFv.Id = outerFvi.FlowVersionId
JOIN FlowVersionItems newFvItems ON newFvItems.FlowVersionId = 143
WHERE outerFv.Id = 133
AND outerFvia.Deleted = 0 AND outerFvi.Deleted = 0 AND outerFv.Deleted = 0 AND newFvItems.Deleted = 0
group by newFvItems.Id, outerFvia.[UserRoleId]
Hopefully me posting the solutions i came up with helps someone else, i know this question gets asked a lot and if it wasn't for the joins it would be a lot easier.
I know that my question would be duplicated but I really don't know how to created sql which return results of sum with multiple join.
Tables I have
result_summary
num_bin id_summary count_bin
3 172 0
4 172 0
5 172 0
6 172 0
7 172 0
8 172 0
1 174 1
2 174 0
3 174 0
4 174 0
5 174 0
6 174 0
7 174 0
8 174 0
1 175 0
summary_assembly
num_lot id_machine sabun date_work date_write id_product shift count_total count_fail count_good id_summary id_operation
adfe 1 21312 2020-11-25 2020-11-25 1 A 10 2 8 170 2000
adfe 1 21312 2020-11-25 2020-11-25 1 A 1000 1 999 171 2000
adfe 1 21312 2020-11-25 2020-11-25 2 A 100 1 99 172 2000
333 1 21312 2020-12-06 2020-12-06 1 A 10 2 8 500 2000
333 1 21312 2020-11-26 2020-11-26 1 A 10000 1 9999 174 2000
333 1 21312 2020-11-26. 2020-11-26 1 A 100 0 100 175 2000
333 1 21312 2020-12-06 2020-12-06 1 A 10 2 8 503 2000
333 1 21312 2020-12-07 2020-12-07 1 A 10 2 8 651 2000
333 1 21312 2020-12-02 2020-12-02 1 A 10 2 8 178 2000
employees
sabun name_emp
3532 Kim
12345 JS
4444 Gilsoo
21312 Wayn Hahn
123 Lee too
333 JD
info_product
id_product name_product
1 typeA
2 typeB
machine
id_machine id_operation name_machine
1 2000 name1
2 2000 name2
3 2000 name3
4 3000 name1
5 3000 name2
6 3000 name3
7 4000 name1
8 4000 name2
query
select S.id_summary, I.name_product, M.name_machine,
E.name_emp, S.sabun, S.date_work,
S.shift, S.num_lot, S.count_total,
S.count_good, S.count_fail,
sum(case num_bin when '1' then count_bin else 0 end) as bin1,
sum(case num_bin when '2' then count_bin else 0 end) as bin2,
sum(case num_bin when '3' then count_bin else 0 end) as bin3,
sum(case num_bin when '4' then count_bin else 0 end) as bin4,
sum(case num_bin when '5' then count_bin else 0 end) as bin5,
sum(case num_bin when '6' then count_bin else 0 end) as bin6,
sum(case num_bin when '7' then count_bin else 0 end) as bin7,
sum(case num_bin when '8' then count_bin else 0 end) as bin8
from result_assembly as R
join summary_assembly as S on R.id_summary = S.id_summary
join employees as E on S.sabun = E.sabun
join info_product as I on S.id_product = I.id_product
join machine as M on S.id_machine = M.id_machine
where I.id_product = '1'
and E.sabun='21312'
and S.shift = 'A'
and S.date_work between '2020-11-10' and '2020-12-20'
group by S.id_summary, E.name_emp, S.num_lot,
I.name_product,M.name_machine
order by S.id_summary;
result
id_summary name_product name_machine name_emp sabun date_work shift num_lot count_total count_good count_fail bin1 bin2 bin3 bin4 bin5 bin6 bin7 bin8
170 TypeA name1 Kim 21312 2020-11-25 A adfe 10 8 2 1 1 0 0 0 0 0 0
171 TypeA name1 Kim 21312 2020-11-25 A adfe 1000 999 1 1 1 0 0 0 0 0 0
174 TypeA name1 Kim 21312 2020-11-26 A 333 10000 9999 1 1 1 0 0 0 0 0 0
175 TypeA name1 Kim 21312 2020-11-26 A 333 100 100 0 0 0 0 0 0 0 0 0
178 TypeA name1 Kim 21312 2020-12-02 A 333 10 8 2 1 1 0 0 0 0 0 0
179 TypeA name1 Kim 21312 2020-12-02 A 333 10 8 2 1 1 0 0 0 0 0 0
180 TypeA name1 Kim 21312 2020-12-02 A 333 10 8 2 1 1 0 0 0 0 0 0
181 TypeA name1 Kim 21312 2020-12-02 A 333 10 8 2 1 1 0 0 0 0 0 0
182 TypeA name2 Kim 21312 2020-12-02 A 333 10 8 2 1 1 0 0 0 0 0 0
186 TypeA name2 Kim 21312 2020-12-06 A 333 10 8 2 1 1 0 0 0 0 0 0
193 TypeA name2 Kim 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
194 TypeA name2 Kim 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
195 TypeA name2 Kim 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
196 TypeA name2 JS 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
197 TypeA name2 JS 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
198 TypeA name2 JS 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
199 TypeA name2 JS 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
200 TypeA name2 JS 21312 2020-12-06 A 333 10 8 2 0 0 0 0 0 0 0 0
expected output(when sum by num_lot)
num_lot count_total count_good count_fail bin1 bin2 bin3 bin4 bin5 bin6 bin7 bin8
adfe 323 300 23 22 1 0 0 0 0 0 0
333 4312 4300 12 10 2 0 0 0 0 0 0
All of them were modified from original one because they were non-English, so there would be typo.
Here now I need to sum by num_lot, name_product or sabun.
id_summary is unique.
Thanks
As expected in the comments: It seems like you simple need a subquery which groups your table by the column num_lot
SELECT
num_lot,
SUM(count_total),
SUM(count_good)
-- some more SUM()
FROM (
--<your query>
) s
GROUP BY num_lot
It was asked in the comments what the s stands for: A subquery needs an alias, an identifier. Because I didn't want to think about a better name, I just called the subselect s. It is the shortcut for AS s
It sounds like you want to use crosstab() -- https://www.postgresql.org/docs/current/tablefunc.html
I'm in the middle of optimizing a query and notice that it becomes really slow because it estimated the number of rows to be 16.6 and the actual number of rows being returned is 565824. I updated the statistic, dropped and recreated but it still gives the incorrect estimate. This is for SQL Server 2016, any help is appreciated.
SQL:
select cd_key
from dbo.CAMPDIV
where cd_camp = 'a'
and CD_CAMPYR = '2018'
option (recompile)
Histogram for nonclustered index (cd_campyr)
All Density Average Length Columns
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0.02040816 4 CD_CAMPYR
7.412665E-08 8 CD_CAMPYR, CD_ID
7.184833E-08 18 CD_CAMPYR, CD_ID, CD_CAMP
Histogram Steps
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 792181 0 1
1979 0 230 0 1
1980 0 332 0 1
1981 0 604 0 1
1982 0 622 0 1
1983 0 330 0 1
1984 0 1762 0 1
1985 0 868 0 1
1986 0 551 0 1
1987 0 190 0 1
1988 0 352 0 1
1989 0 519 0 1
1990 0 38829 0 1
1991 0 439486 0 1
1992 0 366357 0 1
1993 0 375469 0 1
1994 0 369176 0 1
1995 0 367691 0 1
1996 0 376979 0 1
1997 0 388239 0 1
1998 0 391408 0 1
1999 0 402551 0 1
2000 0 413392 0 1
2001 0 422470 0 1
2002 0 461895 0 1
2003 0 458726 0 1
2004 0 459876 0 1
2005 0 473357 0 1
2006 0 464213 0 1
2007 0 472373 0 1
2008 0 457623 0 1
2009 0 462268 0 1
2010 0 465633 0 1
2011 0 470338 0 1
2012 0 472091 0 1
2013 0 481586 0 1
2014 0 484236 0 1
2015 0 492460 0 1
2016 0 514569 0 1
2017 0 551739 0 1
2018 0 571969 0 1
2019 0 552550 0 1
2020 0 54 0 1
2021 0 33 0 1
2022 0 21 0 1
2023 0 8 0 1
2025 1 1 1 1
2099 0 1 0 1
It is a bit strange what you tell but in any case... a covering index may help or even produce a drastic increase.
Please, try to create the index:
CREATE INDEX IX_CampDiv_CD_Camp_CD_CampYR ON dbo.CAMPDIV (cd_camp, CD_CAMPYR )
INCLUDE (cd_key)
At least will prevent the Nested Loop what improves the plan.
Please, share the results.
ID jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
13441 37 0 0 0 0 67 0 0 0 0 0 0
13555 37 0 97 0 0 0 0 0 0 0 0 0
15103 67 0 97 0 0 0 0 0 0 0 0 0
16019 37 0 97 0 0 0 0 0 0 37 67 97
12951 67 0 97 0 0 0 0 0 0 0 0 0
16351 37 0 37 67 0 0 0 0 0 0 37 67
13244 37 0 37 67 0 0 0 0 0 0 0 0
Hmmm . . . This requires unpivoting the data, filtering, and re-aggregating. This turns out to be pretty easy using apply:
select t.*, c.cnt37
from t outer apply
(select count(*) as cnt37
from (values (jan), (feb), (mar), (apr), (may), (jun), (jul), (aug), (sep), (oct), (nov), (dec)
) v(val)
where val = 37
) c;
You can use UNPIVOT:
SELECT ID, COUNT(*) AS cnt
FROM (
SELECT *
FROM mytable) AS src
UNPIVOT (col FOR mon IN ([Jan], [Feb], [Mar], [Apr], [May], [Jun],
[Jul], [Aug], [Sep], [Oct], [Nov], [Dec])) AS unpvt
WHERE col = 37
GROUP BY ID
I have table like this, name: Table.dbo
Amount Desc Month SM code ID
$32,323.00 Bla1 1 121 3 2424221
$4,242.00 Bla2 1 A1 3 2424221
$3,535.00 Bla3 1 A3 1 3230824
$4,984.00 Bla4 1 433 1 3230824
$47,984.00 Bla5 1 B1 1 3230824
$3,472.00 Bla6 1 D2 27 2297429
$3,239.00 Bla7 1 124 27 2297429
$4,249.00 Bla8 1 114 24 3434334
$2,492.00 Bla9 1 132 24 3434334
$424.00 Bla10 2 232 3 2424221
$24,242.00 Bla7 2 124 3 2424221
$242,424 Bla4 2 433 1 3230824
$533.00 Bla13 2 235 1 3230824
$4,342.00 Bla14 2 223 1 3230824
$24,242.00 Bla15 2 224 27 2297429
$24,242.00 Bla1 2 121 27 2297429
$4,242.00 Bla17 2 432 24 3434334
$24,224.00 Bla9 2 132 24 3434334
I wrote this query :
select
[SM],
count(*) as TotalCntOfSM,
sum(case when [code] between 4 and 27 then 1 else 0 end) as TotalCntOfSM_R,
sum(case when [code] in (1,2,3) then 1 else 0 end) as TotalCntOfSM_B,
sum(case when [code] in (1) then 1 else 0 end) as TotalCntofSM_B1,
sum(case when [code] in (2) then 1 else 0 end) as TotalCntofSM_B2,
sum(case when [code] in (3) then 1 else 0 end) as TotalCntofSM_B3,
sum([Amount]) As TotalAmount
****[How can I sum the Amount for the SM if the code is between 4 and 27?** For example]**
from [Table]
group by [SM]
order by TotalCntOfSM desc
How can I sum the Amount for the SM if the code is between 4 and 27 or the code is in (1,2,3) only (For example).
Thank you very much!
Exactly like qxg said - Replace
****[How can I sum the Amount for the SM if the code is between 4 and 27?** For example]** `
with
sum(case when [code] between 4 and 27 then [Amount] else 0 end) as SMAmount
If you want to total up amount for code between 4 and 27 or for codes 1,2,3
sum(case when [code] between 1 and 27 then [Amount] else 0 end) as SMAmount
You can write the above also as
sum(case when [code] between 4 and 27 OR [code] in (1,2,3) then [Amount] else 0 end) as SMAmount