Using COUNT with CASE, how do I order resulting columns? - mysql

I have the following code:
SELECT COUNT(CASE WHEN Title LIKE '%Superintendent%' THEN 1 END) AS 'Bob',
COUNT(CASE WHEN Title LIKE '%Machine%' THEN 1 END) AS 'Control',
COUNT(CASE WHEN Title LIKE '%Estimator%' THEN 1 END) AS 'Estimator'
FROM pants;
Current result looks like this:
Bob Control Estimator
230 550 1243
Instead, I would like the resulting view from the query to have the columns in descending order: Estimator --> Control --> Bob

It's not recommended to mess around dynamically with the order of columns in the result set. The query should, instead, have a result set with a highly predictable (ideally static) set of columns.
To re-order the columns is, I'd recommend, the job of whatever renders that result set after the database returns it.

SQLs sorting is designed to order rows, not columns. In order to change the column order in your output, you would need to order your data, then build a dynamic query to return the columns in the right order. However, it is a lot easier just to do the first part (ordering your data) if a result like this would be acceptable for what you need.
Name Total
Estimator 1243
Control 550
Bob 230
This query could look something like this (my MySQL syntax is rusty, but this should be close)
SELECT 'Bob' as Name, COUNT(CASE WHEN Title LIKE '%Superintendent%' THEN 1 END) AS Total From Pants
UNION ALL
SELECT 'Control' as Name, COUNT(CASE WHEN Title LIKE '%Machine%' THEN 1 END) AS Total From Pants
UNION ALL
SELECT 'Estimator' as Name, COUNT(CASE WHEN Title LIKE '%Estimator%' THEN 1 END) AS Total From Pants
ORDER BY Total desc;

;
WITH cte AS
(
SELECT dtls,
pantcounts
FROM (
SELECT Count(
CASE
WHEN title LIKE '%Superintendent%' THEN 1
END) AS 'Bob',
Count(
CASE
WHEN title LIKE '%Machine%' THEN 1
END) AS 'Control',
Count(
CASE
WHEN title LIKE '%Estimator%' THEN 1
END) AS 'Estimator'
FROM pants) P UNPIVOT (pantcounts FOR dtls IN (bob,
[Control],
[Estimator])) AS unp
select dtls,
pantcounts,
row_number() OVER (ORDER BY pantcounts DESC) AS rownum
FROM cte
This will give the required sorted data in row. Then service layer should do the transpose from rows to column.

Related

want to get all dates but when there is one or more TDBUY = 1 then this date#TDBUY=0 not

I have a table with a date column and a column named TDBUY (which can be 0 or 1). Now I do following:
SELECT tradedate,aktienstat.TDBuyPerfection,count(*) as cc from
aktienstat group by TradeDate,TDBuyPerfection HAVING cc >= '0' ORDER
BY TradeDate desc limit 100;
And get:
I don`t want to display f.e. the 2018-02-08 or 2018-02-07 with 0 count (line 1 and line 3) because there are 1 count with 1 each. But if no TDBUY then the date should be displayed with 0 count.
Can anyone here tell me please how to do it?
THANKS
Edit: It works also fine with SUM instead of Count.
SELECT tradedate,aktienstat.TDBuyPerfection,sum(aktienstat.TDBuyPerfection) as summe from
aktienstat group by TradeDate ORDER
BY TradeDate desc limit 100;ยด
We can try doing this via a pivot query:
SELECT
tradedate,
CASE WHEN cnt_1 = 0 THEN 0 ELSE 1 END AS TDBuyPerfection,
CASE WHEN cnt_1 = 0 THEN cnt_0 ELSE cnt_1 END AS cnt
FROM
(
SELECT
tradedate,
COUNT(CASE WHEN TDBuyPerfection = 0 THEN 1 END) AS cnt_0,
COUNT(CASE WHEN TDBuyPerfection = 1 THEN 1 END) AS cnt_1
FROM aktienstat
GROUP BY tradedate
) t;
The pivot trick works here because it brings the zero and one counts into a single record. There, it is relatively easy to test both counts. In your current form, it is much harder to check the counts.
The demo below shows that zero buy dates appear with only the zero count, while dates having a buy count show only the buy data.
Demo

SQL How to create a value for a new column based on the count of an existing column by groups?

I have a temp table that I'm reading from, and I want to look at one of the columns that only has two grade values - either a 3 or a 4 and build two new columns - one that holds the count of the 3's and the other to hold the count of the 4's - by a particular grouping. My code looks like this.
Select Max(Counting) as Total
, student
, stdType
, Score3 = (SELECT count(*) from #tempBWMSHonors3 where score = '3')
, Score4 = (SELECT count(*) from #tempBWMSHonors3 where score = '4')
from #tempBWMSHonors3
group by student, stateID, grade, stdType
I also embedded an image that show an example of my temp table and what I'm trying to achieve (as well as the result I am getting - but don't want).
[]
I think you just want conditional aggregation, not subqueries:
select Max(Counting) as Total, student, stdType,
sum(case when score = '3' then 1 else 0 end) as Score3,
sum(case when score = '4' then 1 else 0 end) as Score4
from #tempBWMSHonors3
group by student, stdType;
Note: if score is a number and not a string, then you should not use single quotes for the constant.

Several select count(*) in a single query

I have a mysql table(tbl_subscriptiondetails) like the above.Here the last column i.e
'test_status' could have possible values C,S & Y only.
Using a single query i would like to fetch data in the manner
as shown below
But the query that i'm using gives me undesired results.My query is
SELECT pkg_name,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='C' AND mem_id=3) AS completed,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='S' AND mem_id=3) AS started,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='Y' AND mem_id=3) AS remaining
FROM tbl_subscriptiondetails
WHERE mem_id=3
GROUP BY pkg_name
and the result is
Please advise what is wrong. Thanks in advance.
You are running a subquery for each count, instead of counting as part of the main query. Therefore, your filter conditions aren't behaving as you expect them to. You can change it like so, to do the conditional count:
SELECT pkg_name,
SUM( case when test_status='C' then 1 else 0 end) AS completed,
SUM( case when test_status='S' then 1 else 0 end) AS started,
SUM( case when test_status='Y' then 1 else 0 end) AS remaining
FROM tbl
WHERE mem_id = 3
GROUP BY pkg_name
Demo

Select rows grouped by keyword but weight each group instead of using COUNT()

I use MySQL database server and I have a table named keywords with the following structure:
kewyord_name | product_id
As well as a list of keywords. I can sort the keywords table based on the list with the following query:
SELECT *, COUNT(*)
FROM keywords
WHERE keyword_name IN (comma separated list of keywords)
GROUP BY product_id
HAVING COUNT(*) > 2
ORDER BY COUNT(*) DESC
Is there a way to add weight to the keywords, i.e. for some of the keywords the COUNT(*) to be increased with more than one?
Using the COUNT(*) function you'll only be able to increment by one with each row. If you want keywords to be treated differently, you could use the SUM() function with a case block.
For example, let's say you have keywords This, that, these. If you want keyword this and that to have a weight of 3, these a weight of 2, and anything else a weight of 1, you can do this:
SELECT keyword_name,
SUM(CASE WHEN keyword_name IN ('this', 'that') THEN 3
WHEN keyword_name IN ('these') THEN 2
ELSE 1 END) AS weight
FROM myTable
GROUP BY keyword_name;
Here is an SQL Fiddle example.
To match the design of your query you have already, you just need to add your having and order by clauses:
SELECT keyword_name,
SUM(CASE WHEN keyword_name IN ('this', 'that') THEN 3
WHEN keyword_name IN ('these') THEN 2
ELSE 1 END) AS weight
FROM myTable
GROUP BY keyword_name
HAVING weight > 2
ORDER BY weight DESC;
If you add a column 'weight' to the keywords table you can use Sum(Weight) and Having Sum(Weight) instead of Count(*)...
Edit:
select productid, Sum(weights.weight)
from Keywords
Join (Select 'keyword1' as keyword, 2 as weight
Union All
Select 'keyword2' , 5
Union All
Select 'keyword3', 6
) as weights
on Keywords.keyword_name = weights.keyword
group by productid
having Sum(weights.weight) > somevalue
order by weights.weight desc

Alternative to "IN" that works like "AND" instead of "OR"

From my understanding, IN works like this:
$arrayName = array(1, 2, 3);
SELECT *
FROM tableName
WHERE productID IN ($arrayName)
is the equivalent of:
SELECT *
FROM tableName
WHERE productID = 1 OR productID = 2 OR productID = 3
I'm wondering if there's a SQL function that works like IN but uses AND in place of OR to compare to an array. Something that would expand to this:
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
Not that it's necessary, but for context I'm simply creating a sort list for some search results that are being populated on a PHP page via jQuery. I can do what I need with PHP, I'll simply create the query dynamically depending on what options the user has selected, but I'd rather use an intelligent SQL function if possible.
***EDIT: Thanks everyone for the help. I explained my problem very poorly and you were still able to sort it out, which I appreciate. I found that someone else had asked this question more eloquently and received an answer that I can use:
Is there something in MySQL like IN but which uses AND instead of OR?
I'm trying to figure out how to accept an answer and close this but I'm having a bit of trouble...
You cannot possibly do this,
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
the condition will always returns false because a row can have only one value on its column, the alternative way to do this is by grouping the result, ex.
SELECT colName
FROM tableName
WHERE productID IN (1,2,3)
GROUP BY colName
HAVING COUNT(DISTINCT colName) = 3
by having a condition HAVING COUNT(DISTINCT colName) = 3, this means that the instance of a record must be equal to the total count of parameters supplied on IN clause.
As written, your query will produce no rows. It is not possible for productID in a row to be equal to both 1 and 2 at the same time.
You are probably looking for a group of rows that contain these three products. Say you want to find orders that have all three products. You can use something like:
select orderid
from orderlines ol
group by orderid
havnig max(case when ol.productid = 1 then 1 else 0 end) > 0 and
max(case when ol.productid = 2 then 1 else 0 end) > 0 and
max(case when ol.productid = 3 then 1 else 0 end) > 0
The GROUP BY with the HAVING clause will find orders where all three products are present.
SELECT orderid
FROM tableName
WHERE productID IN (1, 2, 3)
GROUP BY orderid
HAVING COUNT(DISTINCT productID) = 3 --this number must match the number of unique IDs in the IN clause