MySQL count with group by - mysql

Sorry for an unclear question, my english isnt that good. So theres my query:
SELECT ticketID,
status,
COUNT(status) as count,
statusName,
assign
FROM ticket, department, status
WHERE ticket.department = 100
AND ticket.department = department.departID
AND ticket.status = status.statusID
GROUP BY statusName,assign
and this is the result:
| ticketID | count | statusName | assign |
|:----------|-----------:|:---------:|:-------:
| 1002 | 2 | open | NULL |
| 1020 | 1 | open | James |
| 1021 | 1 | open | Nick |
| 1015 | 1 | overdue | NULL |
My goal was to count ticket by their status, and if status='open' and assign = null then the status would change to 'unassigned', i need a better solution or just a way to merge the result where 'James' and 'Nick' to be one, as i only need to know whether the ticket is assigned or not.

Don't see where you need department table, think you can remove it safely, but...
SELECT a.statusID, a.Status, Count(*)
FROM(
SELECT statusID,
(CASE WHEN statusName = 'open' and assign IS NULL THEN 'unassigned'
WHEN statusName ='open' and assign IS NOT NULL THEN 'assigned'
ELSE statusName
END) as Status
FROM ticket
INNER JOIN department ON ticket.department = department.departID
INNER JOIN status ON ticket.status = status.statusID
WHERE ticket.department = 100) as a
GROUP BY a.Status, a.statusID
SqlFiddle (simplified)

SELECT ticketID,
status,
COUNT(status) as count,
statusName,
'unassigned'
FROM ticket, department, status
WHERE ticket.department = 100
AND ticket.department = department.departID
AND ticket.status = status.statusID
AND assign is NULL
GROUP BY statusName
UNION
SELECT ticketID,
status,
COUNT(status) as count,
statusName,
'assigned'
FROM ticket, department, status
WHERE ticket.department = 100
AND ticket.department = department.departID
AND ticket.status = status.statusID
AND assign is NOT NULL
GROUP BY statusName
This query fetches the unassigned and assigned tickets in the form of a union of two disjoint resultsets.

SELECT ticketID,status,sum(CASE status
WHEN 'open' then 1
WHEN '' then 1
WHEN NULL then 1
else 0) as count,statusName,assign
FROM ticket, department, status WHERE ticket.department = 100
AND ticket.department = department.departID
AND ticket.status = status.statusID
GROUP BY statusName,assign

Related

How to get the result in single row when using sub queries in SQL Server 2008?

I am trying to get a table with stage_name and its count in respective loan product. Like in below example stage_name is RCO and there are three loan product, Auto loan, Consumer loan and Credit card. Though I have used the logic and getting the right output, but in the output, I am getting the separate row for each stage_name and loan product case. I want only one row with all the three result. Please look at my code below, actual output and desired output:
SELECT
'RCO',
CASE
WHEN sq2.loan_type = 'Consumer loan'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Consumer_Loan,
CASE
WHEN sq2.loan_type = 'Auto Loan'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Auto_Loan,
CASE
WHEN sq2.loan_type = 'Credit Card'
THEN SUM(ISNULL(sq2.user_count, 0))
END AS Credit_Card
FROM
(SELECT
'RC0' AS ws_name, 'Consumer loan' AS loan_type,
COUNT(DISTINCT a.bpm_referenceno) AS user_count,
a.takenby AS user_id
FROM
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM
BM_RLOS_EXTTABLE m
WHERE
m.loan_type = 'Consumer Loan') sq1 ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE
a.winame='RCO'
GROUP BY
a.takenby
UNION
SELECT 'RC0','Auto loan',
count (DISTINCT a.bpm_referenceno), a.takenby
from
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM BM_RLOS_EXTTABLE m
WHERE m.loan_type='Auto Loan')sq1
ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE a.winame='RCO'
GROUP BY a.takenby
UNION
SELECT 'RC0','Credit Card',
count (DISTINCT a.bpm_referenceno), a.takenby
from
BM_RLOS_DecisionHistoryForm a
INNER JOIN
(SELECT
m.bpm_referenceno
FROM BM_RLOS_EXTTABLE m
WHERE m.loan_type='Credit Card')sq1
ON a.bpm_referenceno = sq1.bpm_referenceno
WHERE a.winame='RCO'
GROUP BY a.takenby) sq2
GROUP BY sq2.ws_name,sq2.loan_type
Actual output:
|--------------|-------------|-------------|-------------|
| Stg_nm | Cons_ln | Auto_lan | Credit_card |
|--------------|-------------|-------------|-------------|
| RCO | NULL | NULL | 8 |
|--------------|-------------|-------------|-------------|
| RCO | NULL | 55 | NULL |
|--------------|-------------|-------------|-------------|
| RCO | 81 | NULL | NULL |
|--------------|-------------|-------------|-------------|
Required Output
|--------------|-------------|-------------|-------------|
| Stg_nm | Cons_ln | Auto_lan | Credit_card |
|--------------|-------------|-------------|-------------|
| RCO | 81 | 55 | 8 |
|--------------|-------------|-------------|-------------|
The top half should be like this - reverse the usage of SUM and CASE, and remove the last GROUP BY altogether
SELECT
'RCO',
SUM(CASE
WHEN sq2.loan_type = 'Consumer loan'
THEN sq2.user_count
ELSE 0 END
)
AS Consumer_Loan,
SUM(CASE
WHEN sq2.loan_type = 'Auto loan'
THEN sq2.user_count
ELSE 0 END
)
AS Auto_Loan,
SUM(CASE
WHEN sq2.loan_type = 'Credit Card'
THEN sq2.user_count
ELSE 0 END
)
AS Credit_Card
FROM
<your existing query, with the final GROUP BY removed>
But you need to remove the GROUP BY from the end altogether

mySQL Query select / join not working as expected

let me preface that I've done a good bit of searching to see if this issue can be resolved but have yet to find an answer that relates, so I'll ask now. I have a query that works (mostly) to pull from two separate tables to show a total amount of pc models in each of four locations(these locations are in a single column, so I'm trying to select them as their own columns through aliases). The query pulls all required info, but not as I was hoping it would.
Expectation:
model | loc1 | loc2 | loc3 | loc4
5530 | 3 | 2 | 1 | 0
6440 | 10 | 0 | 3 | 20
Reality:
model | loc1 | loc2 | loc3 | loc4
5530 | 3 | null | null | null
5530 | null | 2 | null | null
5530 | null | null | 1 | null
etc..
Here is my query, any help to make the reality match the expectation if possible would be appreciated.
SELECT
a.model,
(select COUNT(a.model)
WHERE a.location = 'AoC-Reno') AS Reno,
(select count(a.model)
where a.location = 'AoC-Fargo') AS Fargo,
(select count(a.model)
where a.location = 'EoC') AS EoC,
(select count(a.model)
where a.location = 'APoC') as APoC
FROM assets AS a
join models m on m.model = a.model
WHERE m.type IN ('Desktop','Laptop')
AND a.model = m.model
AND a.status != 'Recycled'
GROUP BY m.model, a.location
ORDER BY m.model
Use conditional aggregation:
SELECT a.model,
SUM(a.location = 'AoC-Reno') AS Reno,
SUM(a.location = 'AoC-Fargo') AS Fargo,
SUM(a.location = 'EoC') AS EoC,
SUM(a.location = 'APoC') as APoC
FROM models m JOIN
assets a
on m.model = a.model
WHERE m.type IN ('Desktop', 'Laptop') and a.status <> 'Recycled'
GROUP BY m.model
ORDER BY m.model;
Your query has multiple issues:
You are using a "subquery", but there is no FROM clause.
You are aggregating by both model and location, but you want only one row per model.
The JOIN condition is both in the ON clause and repeated in the WHERE clause.
You can do a conditional aggregation (count)
SELECT a.model,
SUM(CASE WHEN a.location = 'AoC-Reno' THEN 1 END) reno,
SUM(CASE WHEN a.location = 'AoC-Fargo' THEN 1 END) farggo,
SUM(CASE WHEN a.location = 'EoC' THEN 1 END) eoc,
SUM(CASE WHEN a.location = 'APoC' THEN 1 END) apoc
FROM assets AS a JOIN models m
ON m.model = a.model
WHERE m.type IN ('Desktop','Laptop')
AND a.status != 'Recycled'
GROUP BY m.model
ORDER BY m.model

how to make a SELECT that merges duplicated Primary Keys

I'm performing a query that looks like this:
SELECT a.transactionID,a.customerID,b.value
FROM adjustments a
INNER JOIN change b
on a.transactionID = b.transactionID
and a.event_date = b.event_date
and a.event_id = b.event_id
WHERE comment LIKE 'TRANSFER'
ORDER BY a.transactionID;
this query brings the following result:
transactionID | customerID | value
------------------------------------
TRANSFER-001 | CUSTA | -200
TRANSFER-001 | CUSTB | 200
TRANSFER-002 | CUSTC | -150
TRANSFER-002 | CUSTD | 0
TRANSFER-003 | CUSTA | 0
TRANSFER-003 | CUSTC | 150
I need to change this query to bring a list that ignore those cases where the sum of value is 0 for the same transactionID and also, group the customerID and values as following:
transactionID | customerID_A | value_A | customerID_B | value_B
------------------------------------------------------------------
TRANSFER-002 | CUSTC | -150 | CUSTD | 0
TRANSFER-003 | CUSTA | 0 | CUSTC | 150
Can you give any advise about how to solve this?
Try this :
SELECT * FROM (
SELECT a.transactionID,a.customerID,b.value
FROM adjustments a
INNER JOIN change b
on a.transactionID = b.transactionID
and a.event_date = b.event_date
and a.event_id = b.event_id
WHERE comment LIKE 'TRANSFER'
)M
GROUP BY transactionID,customerID,value
HAVING SUM(value) <> 0
ORDER BY transactionID;
SELECT distinct a.transactionID,a.customerID,b.value
FROM adjustments a
INNER JOIN change b
on a.transactionID = b.transactionID
and a.event_date = b.event_date
and a.event_id = b.event_id
WHERE comment LIKE 'TRANSFER'
ORDER BY a.transactionID;
Try distinct at the beginning it will eliminate all the duplicate values.
If I understand correctly, you want conditional aggregation. However, you need to pivot the customers and there is no column for doing that. You can enumerate the customers for each transaction using variables, and use that to pivot the first two customers on the transaction:
SELECT transactionId,
MAX(CASE WHEN seqnum = 1 THEN customerId END) as customer_A,
MAX(CASE WHEN seqnum = 1 THEN value END) as value_A,
MAX(CASE WHEN seqnum = 2 THEN customerId END) as customer_B,
MAX(CASE WHEN seqnum = 2 THEN value END) as value_B
FROM (SELECT a.transactionID, a.customerID, b.value,
(#rn := if(#t = a.transactionID, #rn + 1,
if(#t := a.transactionID, 1, 1)
)
) as seqnum
FROM adjustments a INNER JOIN
change c
ON a.transactionID = c.transactionID AND
a.event_date = c.event_date AND
a.event_id = c.event_id CROSS JOIN
(SELECT #rn := 0, #t := '') params,
WHERE comment LIKE 'TRANSFER'
ORDER BY a.transactionID, b.value DESC
) t
GROUP BY transactionId
HAVING SUM(value) <> 0;

AND? OR? IF? count the orders complying 2 conditions

I have 2 tables:
1st t "ORDERS" - columns: customer nr, order nr, payment method
2nd t "STATUSES" - columns: order nr, the order status
I want to count for specific customers, the amount of:
'shipped' orders paid by credit card (CC)
plus amount of 'canceled' orders paid another way.
I would like to have the result in one column.
select c_id, count(*)
from orders o
join statuses s on o.o_nr = s.o_nr
where o.c_id in (1, 2)
?
group by o.c_id
In details:
ORDERS
c_id | o_nr | pm
1 | 0004 | CC
1 | 0009 | CC
2 | 0011 | CC
2 | 0018 | installment
2 | 0020 | gift ;)
STATUSES
o_nr | status
0004 | shipped
0009 | in_progress
0011 | shipped
0018 | canceled
0020 | canceled
The result should be:
c_id | count (*)
1 | 1
2 | 3
Here's one approach:
SELECT o.c_id
, COUNT(*)
FROM orders o
JOIN statuses s
ON s.o_nr = o.o_nr
AND ( (s.status = 'shipped' AND o.pm = 'CC')
OR (s.status = 'canceled' AND o.pm <> 'CC')
)
WHERE o.c_id in (1, 2)
GROUP BY o.c_id
For this type of query, I sometimes find it advantageous to move the conditional tests into expressions in the SELECT list; this is useful when I want to return 0 counts, and I want to include the same rows in more than one "count"...
For example:
SELECT o.c_id
, SUM(s.status = 'shipped' AND o.pm = 'CC') AS shipped_and_cc
, SUM(s.status = 'canceled' AND o.pm <> 'CC') AS canceled_not_cc
, SUM((s.status = 'shipped' AND o.pm = 'CC')
OR (s.status = 'canceled' AND o.pm <> 'CC')) AS sac_and_cnc
, SUM(1) AS total_orders
FROM orders o
JOIN statuses s
ON s.o_nr = o.o_nr
WHERE o.c_id in (1, 2)
GROUP BY o.c_id

Complex IF statement with 3 tables

This is a continuation of this question from yesterday.
Here are my three tables:
Fighters Table
fighter_id | name
-----------------------
1 | John
2 | Steve
3 | Bill
4 | Bobby
Events Table
event_id | event_name | event_date
-------------------------------------------
1 | MMA | 01/01/2010
2 | Cool | 02/20/2010
3 | Yeaa! | 04/15/2010
Fights Table
fight_id | fighter_a | fighter_b | winner | method | event
-----------------------------------------------------------------------
1 | 1 | 2 | 1 | Sub | 1
2 | 4 | 1 | 4 | KO | 2
3 | 1 | 3 | NULL | Draw | 3
Result trying to get
result | opponent | method | event | date
----------------------------------------------------------
Draw | Bill | Draw | Yeaa! | 04/15/2010
Loss | Bobby | KO | Cool | 02/20/2010
Win | Steve | Sub | MMA | 01/01/2010
So in the fights table, fighter_a, fighter_b, and winner are integers that correspond to fighter_id in the Fighters table.
I'm basically on a page retrieving data based on fighter_id ($fighter_id).
I'm trying to create rows with each fight of that fighter that includes his opponent's name, result (win, loss, draw, or nc), method, event_name, and event_date. The challenge is that a winner can be in either fighter_a or fighter_b. It's not always in the same column. I appreciate any help I can get.
select
fight_id,
CASE
WHEN winner is not null and winner=fighter_id then 'win'
WHEN winner is not null and winner<>fighter_id then 'loss'
WHEN winner is null and method='Draw' then 'draw'
WHEN winner is null and method = 'No Contest' then 'no contest'
ELSE ''
END as match_result,
participant.name 'participant',
opponent.name 'opponent'
FROM fights
INNER JOIN fighters as participant on participant.fighter_id = fights.fighter_a
INNER JOIN fighters as oppoent on opponent.fighter_id = fights.fighter_b
WHERE
fighter_a=$fighter_id OR fighter_b=$fighter_id
ORDER BY
event_date DESC
Use a subselect with conditionals to switch the fighter_id you're looking for to column_a if it's in column_b, that way, it simplifies your operations and joins in the outer query:
SELECT
(
CASE
WHEN a.winner = a.f_a THEN 'Win'
WHEN a.winner = a.f_b THEN 'Loss'
WHEN a.winner IS NULL THEN a.method
END
) AS result,
b.name AS opponent,
a.method AS method,
c.event_name AS event,
c.event_date AS date
FROM
(
SELECT
IF(fighter_b = $fighter_id, fighter_b, fighter_a) AS f_a,
IF(fighter_b = $fighter_id, fighter_a, fighter_b) AS f_b,
winner,
method,
event
FROM
fights
WHERE
$fighter_id IN (fighter_a, fighter_b)
) a
INNER JOIN
fighters b ON a.f_b = b.fighter_id
INNER JOIN
events c ON a.event = c.event_id
ORDER BY
c.event_date DESC
Also, if the winner field is null, then just echo the method field. That way, when you want to add yet another type of method where winner is null to your system, you don't have to keep tacking on more conditional checks to your CASE statement.
You could use a union:
SELECT CASE WHEN winner = participant_id THEN 'Win'
WHEN winner = opponent_id then 'Loss'
ELSE method
END AS result, fighters.name AS opponent, method, event_name, event_date
FROM fights
INNER JOIN fighters ON fighter_id = opponent_id
INNER JOIN events ON event = event_id
WHERE participant_id = $fighter_id
UNION ALL
SELECT CASE WHEN winner = participant_id THEN 'Loss'
WHEN winner = opponent_id then 'Win'
ELSE method
END AS result, fighters.name AS opponent, method, event_name, event_date
FROM fights
INNER JOIN fighters ON fighter_id = participant_id
INNER JOIN events ON event = event_id
WHERE opponent_id = $fighter_id
ORDER BY event_date DESC
You could just modify you CASE statements to match with $fighter_id.
So your CASE statements would be -
select fight_id,
CASE
WHEN winner is not null and winner = f.fighter_id then 'win'
WHEN winner is not null and winner <> f.fighter_id then 'loss'
WHEN winner is null and method='Draw' then 'draw'
WHEN winner is null and method = 'No Contest' then 'no contest'
ELSE ''
END as match_result,
f.name AS participant,
(SELECT o.name FROM fighters o WHERE o.fighter_id = IF(f.fighter_id = fs.fighter_a, fs.fighter_b, fs.fighter_a)) AS opponent
FROM fights fs,
fighters f
WHERE f.fighter_id = $fighter_id
AND (fs.fighter_a = f.fighter_id OR fs.fighter_b = f.fighter_id)
SELECT
CASE
WHEN winner is not null and winner=fighter_id then 'win'
WHEN winner is not null and winner<>fighter_id then 'loss'
WHEN winner is null and method='Draw' then 'draw'
WHEN winner is null and method = 'No Contest' then 'no contest'
ELSE ''
END result,
f2.name opponent,
method,
event_name event,
event_date date
FROM fights f1
INNER JOIN fighters f2
ON f1.fighter_b = f2.fighter_id
INNER JOIN events e
ON e.event_id = f1.event
ORDER BY date DESC