Multiple counts for each ID - sql

I'm trying to get my head around this, but unfortunately neither of my approaches works:
I need a table with 3 columns:
ItemID
Number cases where ItemID has CostcentreID x
Number cases where ItemID has CostcentreID y
SELECT ItemID, Count1, Count2
FROM Table
Output should be like:
--ItemID--Count1--Count2
1 12 5
2 3 2
What i get when using
SELECT ItemdID, SUM(case when costc...),...
FROM Table
is:
--ItemID--Count1--Count2
1 12 0
2 3 0
due to the GROUP BY statement.
Anyway to solve this without a Cursor?
Also, a JOIN of 5 tables is needed.
Thanks in advance!

I'm not sure what you need with the joins, but here is the first part.
DECLARE #table TABLE(ItemID INT, CostCentreID CHAR(1));
INSERT INTO #table
VALUES (1,'X'),
(1,'X'),
(1,'Y'),
(2,'X'),
(2,'Y'),
(2,'Y'),
(2,'Y');
SELECT ItemID,
SUM(
CASE
WHEN CostCentreID = 'X' THEN 1 ELSE 0
END
) AS CostCentreX,
SUM(
CASE
WHEN CostCentreID = 'Y' THEN 1 ELSE 0
END
) AS CostCentreY
FROM #table
GROUP BY ItemID
Results:
ItemID CostCentreX CostCentreY
----------- ----------- -----------
1 2 1
2 1 3

Related

How to improve UNION of distinct values from the same table with different filters

Background:
The client has the possibility to create his own stock of vehicles. This means that he can display only the vehicles that match his criteria.
He also has the possibility to create frontend filters for users. These filters can synchronize between them. For example, if a user chooses something from filter X, the filter Y shows only the values that match X filter
The performance issue is at populating the frontend filters with values.
What I tried is something like this
;with v as(
select something from vehicles
where [his stock filters])
select 'XFilter',X_id from v where Y_id > [value] and Z_id > [value]
union
select 'YFilter',Y_id from v where X_id > [value] and Z_id > [value]
union
select 'ZFilter',Z_id from v where X_id > [value] and Y_id > [value]
union
...
Multiple unions are going to be added to the query and adding different filters to all of them are hard to index or so I believe.
How should I proceed in order to obtain a better performance? Should I retrieve the data in a different way?
EDIT:
The Vehicles table have columns like the following
ID ColorID FueltypeID Mileage ...
1 1 1 1000
2 1 2 500
3 2 2 2000
4 2 1 1500
5 3 1 9000
6 3 2 8000
Using the above query, I want to extract all the distinct values for filters which have a limited set of values, like colors and fueltypes.
The expected result would be
reference value
1 Color 1
2 Color 2
3 Color 3
4 Fueltype 1
5 Fueltype 2
It is really hard to tell what you want, but it appears to be:
with v as (
select something
from vehicles
where [users stock filters])
)
select f.which, f.id
from v cross apply
(values ('XFilter', v.x_id, (case when Y_id > [value] and Z_id > [value] then 1 else 0 end) ),
('YFilter', v.y_id, (case when X_id > [value] and Z_id > [value] then 1 else 0 end) ),
('ZFilter', v.z_id, (case when X_id > [value] and Y_id > [value] then 1 else 0 end) )
) f(which, id, outcome)
where f.outcome = 1;

DB2 SQL better way to get count of unique values based on ID than SUM+CASE

I am able to count the occurrences of unique values per ID in the same record, but it seems there must be a more efficient way? Something like COUNT([Value],'2')?
Here's a simple example
ID | Value
1 2
1 3
1 3
1 2
2 2
2 3
2 3
3 3
And this is my current code:
SELECT ID, SUM(CASE WHEN Value = '2' THEN 1 ELSE 0 END) AS "COUNT2",
SUM(CASE WHEN Value = '2' THEN 1 ELSE 0 END) AS "COUNT3"
FROM TABLE
GROUP BY ID
The results are:
ID | Count2 | Count3
1 2 3
2 1 2
3 0 1
Is there a better way to get the count of unique values?
Try:
Select distinct Id, Count2, Count3
from Table
Outer Apply (select count(id) as Count2 from table t
where t.id = Table.id and value = 2) c2
Outer Apply (select count(id) as Count3 from table t
where t.id = Table.id and value = 3) c3
Order by Id asc
Typed from my phone so may need to be tweaked a little but something like this should work
You could use DECODE if by "better" you mean more terse
WITH I (ID, V) AS (VALUES
(1,2)
, (1,3)
, (1,3)
, (1,2)
, (2,2)
, (2,3)
, (2,3)
, (3,3)
)
SELECT
ID
, COUNT(DECODE(V,2,1)) AS "Count2"
, COUNT(DECODE(V,3,1)) AS "Count3"
FROM I
GROUP BY
ID
returns
ID Count2 Count3
-- ------ ------
1 2 2
2 1 2
3 0 1
If you are using Db2 LUW 11.1.1.1 onward, you could take advantage of the fact that you can SUM BOOLEAN values.
WITH I (ID, V) AS (VALUES
(1,2)
, (1,3)
, (1,3)
, (1,2)
, (2,2)
, (2,3)
, (2,3)
, (3,3)
)
SELECT
ID
, SUM(V=2) AS "Count2"
, SUM(V=3) AS "Count3"
FROM I
GROUP BY
ID

Checking if the row has the max value in a group

I'm trying get to find out if a row has the max value in a group. Here's really simple example:
Data
VoteCount LocationId UserId
3 1 1
4 1 2
3 2 2
4 2 1
Pseudo-query
select
LocationId,
sum(case
when UserId = 1 /* and has max vote count*/
then 1 else 0
end) as IsUser1Winner,
sum(case
when UserId = 2 /* and has max vote count*/
then 1 else 0
end) as IsUser2Winner
from LocationVote
group by LocationID
It should return:
LocationId IsUser1Winner IsUser2Winner
1 0 1
2 1 1
I also couldn't find a way to generate dynamic column names here. What would be the simplest way to write this query?
You could also do this using a Case statement
WITH CTE as
(SELECT
MAX(VoteCount) max_votes
, LocationId
FROM LocationResult
group by LocationId
)
SELECT
A.LocationId
, Case When UserId=1
THEN 1
ELSE 0
END IsUser1Winner
, Case when UserId=2
THEn 1
ELSE 0
END IsUser2Winner
from LocationResult A
inner join
CTE B
on A.VoteCount = B.max_votes
and A.LocationId = B.LocationId
Try this:
select *
from table t
cross apply (
select max(votes) max_value
from table ref
where ref.group = t.group
)votes
where votes.max_value = t.votes
but if your table is huge and has no propriate indexes performance may be poor
Another way is to get max values by groups into table variable or temp table and then join it to original table.

How to write sql query for this?

My table looks like this:
id staus
1 p
1 p
1 c
2 p
2 c
I need to produce counts of rows with the statuses of 'p' and 'c' for each id, so the result I expect should look like this:
id p c
1 2 1 <-- id 1 has two rows with 'p' and one row with 'c'
2 1 1 <-- id 2 has one row with 'p' and one row with 'c'
How can i achieve this?
You can do it like this:
SELECT
id
, SUM (CASE STATUS WHEN 'p' THEN 1 ELSE 0 END) as p
, SUM (CASE STATUS WHEN 'c' THEN 1 ELSE 0 END) as c
FROM my_table
GROUP BY id
When you have more than just a few fixed items like 'p' and 'c' to aggregate, pivoting may provide a better option.
Pivot solution. Works from sql-server 2008
declare #t table(id int, staus char(1))
insert #t values( 1,'p'),( 1,'p'),( 1,'c'),( 2,'p'),( 2,'c')
SELECT id, [p], [c]
from #t
PIVOT
(count([staus])
FOR staus
in([p],[c])
)AS p
Result:
id p c
1 2 1
2 1 1
It seems that you need to do a pivot of your table, there is a simple article that I used when i faced your same problem pivot table sql server

SQl Server 2005: Rows to columns -- how to do this challenge?

Please let me know, How to convert the following data ,
[id] cost1 cost2 year
1 5 10 2010
1 4 15 2011
2 10 10 2010
into this format [rows of 'Year' to columns heading]
id [cost1-2010] [cost2-2010] [cost1-2011] [cost2-2011]
1 5 10 4 15
2 10 10 0 0
Use PIVOT
example: http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
try something like this:
DECLARE #YourTable table (id int, cost1 int, cost2 int, year int)
INSERT #YourTable VALUES (1,5,10,2010)
INSERT #YourTable VALUES (1,4,15,2011)
INSERT #YourTable VALUES (2,10,10,2010)
SELECT
id
,SUM(CASE WHEN year=2010 THEN cost1 else 0 END) AS "Cost1-2010"
,SUM(CASE WHEN year=2010 THEN cost2 else 0 END) AS "Cost2-2010"
,SUM(CASE WHEN year=2011 THEN cost1 else 0 END) AS "Cost1-2011"
,SUM(CASE WHEN year=2011 THEN cost2 else 0 END) AS "Cost2-2010"
FROM #YourTable
GROUP BY id
OUTPUT
id Cost1-2010 Cost2-2010 Cost1-2011 Cost2-2010
----------- ----------- ----------- ----------- -----------
1 5 10 4 15
2 10 10 0 0
(2 row(s) affected)
If you want to do this dynamically based on data, it is going to be more difficult than just using PIVOT. For PIVOT or the conditional sum technique
[2010Values] = ( SUM(Case when year = 2010 then FieldValue Else 0 End)
you must know the column name ahead of time.
If you wish to set column names dynamically based on the data received then you'll have to go the dynamic SQL route which can get ugly.
Check out the discussion on this post. That should have you dialed.