Add 6 items together to give a total, but by not adding their values together - mysql

Bit of a newbie and probably a very basic question to you, but is driving me mad.
I have a mysql table. I have a record which has a record id, and six other fields which contain names of photographs.
So,
Record_id, photo1, photo2, photo3, photo4, photo5, photo6
I want have have the end result where I have a column called 'TOTAL' which shows the number of how many records have photographs in them as a TOTAL. So, Record 1 may have a total of 5 photographs, record 2 may have 3 photographs, and record 3 may have a total of NO records for that record etc?
Now some of the photographs names which are uploaded to the field may contain numbers, ie, photo244.jpg, or pic3993.jpg etc - so I don't want these numbers added together, I am just looking for whether the field has a name in it etc, and this would be counted as 1 to add to the total. So the end result in on the page is that record 13 (for example) has a total of 4 photographs etc - sorry if not a good explanation!
It may have something to do with SUM or COUNT, but have spent ages trying to get combination or correct key/syntax! Can anyone help please by giving an example of the mysql select statement - would be grateful!

I presume that if there is no photo, then the field photoX is null or is empty.
So use CASE for output 0 if the field is null or empty, 1 else.
SELECT Record_id
,
CASE WHEN (photo1 IS NULL OR photo1 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo2 IS NULL OR photo2 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo3 IS NULL OR photo3 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo4 IS NULL OR photo4 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo5 IS NULL OR photo5 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo6 IS NULL OR photo6 = '') THEN 0 ELSE 1 END
AS Total
FROM myTable

It will the best query:
SELECT
Record_id,
(6 - IFNULL(photo1,1) - IFNULL(photo2,1) - IFNULL(photo3,1) - IFNULL(photo4,1) - IFNULL(photo5,1) - IFNULL(photo6,1)) AS TOTAL
FROM
table

Something like this will give you a count by Photo1, Photo2, etc.:
SELECT
SUM(CASE WHEN photo1 IS NOT NULL THEN 1 END) AS Photo1Count,
SUM(CASE WHEN photo2 IS NOT NULL THEN 1 END) AS Photo2Count,
SUM(CASE WHEN photo3 IS NOT NULL THEN 1 END) AS Photo3Count,
SUM(CASE WHEN photo4 IS NOT NULL THEN 1 END) AS Photo4Count,
SUM(CASE WHEN photo5 IS NOT NULL THEN 1 END) AS Photo5Count
FROM MyTable
Something like this will count how many rows have at least one photograph:
SELECT SUM (
CASE WHEN
photo1 IS NOT NULL OR
photo2 IS NOT NULL OR
photo3 IS NOT NULL OR
photo4 IS NOT NULL OR
photo5 IS NOT NULL THEN 1 END)
FROM MyTable
Note that these queries are for grand totals. They don't show activity by row. If activity by row is needed, try the answers from Scorpi0 or Michael Sivolobov.

Related

How to display duplicate count from two tables where one column duplicate value separate in two column from each table

First of all I want to thank you all members of this community for posting very helpful answers. I am using this kind of plateform first so I am sorry for my grammatical mistakes and if it is a silly question.
I am having a use case as given in below image link.
Having two tables 1. is Office_1 and 2. is Office_2 and want the Desired Output
For this use case I am able to get Output separately only from one table using below query
First query is for one table (Office_1)
select EID as EID,sum(case when OP like 'come' then 1 else 0 end) as 'Office_1 Come COUNT',sum(case when OP like 'go' then 1 else 0 end) as 'Office_1 Go COUNT' from Office_1 where DATE >= '2022-01-16' AND DATE <= '2022-01-18' group by UID;
Second query is for another table (Office_2)
select EID as EID,sum(case when OP like 'come' then 1 else 0 end) as 'Office_2 Come COUNT',sum(case when OP like 'go' then 1 else 0 end) as 'Office_2 Go COUNT' from Office_2 where DATE >= '2022-01-16' AND DATE <= '2022-01-18' group by UID;
But I want that UID must be selected from first table and output must be combined to display. Please help me in this use case. How to get the desired output?
select* from(select EID as EID,sum(case when OP like 'come' then 1 else 0 end) as 'Office_1 Come COUNT',sum(case when OP like 'go' then 1 else 0 end) as 'Office_1 Go COUNT',date as dt from Office_1
union
select EID as EID,sum(case when OP like 'come' then 1 else 0 end) as 'Office_2 Come COUNT',sum(case when OP like 'go' then 1 else 0 end) as 'Office_2 Go COUNT',date as dt from Office_2)
where dt >= '2022-01-16' AND DATE <= '2022-01-18' group by UID;
Please refer here for more information about union select https://dev.mysql.com/doc/refman/8.0/en/union.html

Count of past instances in an appended table

This is my desired output:
CampaignName CampaignDate UsersTargeted CountOfUsersBought
2x1 2018-11-24 1 (UserId 2) 1 (UserId 2)
3x2 2018-11-25 2 (Both) 1 (UserId 1)
'CountOfUsersBought' I want it to be Amongst All Targeted Users.
And the Table (Updated Daily) from where I get the data to fill the previous output has the following structure:
UserId EligibleForOffer(0,1) BoughtToday(0,1) Timestamp
1 0 0 2018-11-24
1 1 0 2018-11-25
1 1 1 2018-11-26
1 0 0 2018-11-27
2 1 0 2018-11-24
2 1 1 2018-11-25
2 1 0 2018-11-26
2 0 1 2018-11-27
I want to store on the variable 'CountOfUsersBought' the count of all the users that actually bought, not only today but all time. How would you go about doing this query?
Please note that users also buy without an offer, so I only want to count the past instances WHERE EligibleForOffer = 1 AND BoughtToday = 1 AND Timestamp <= 'CampaignDate'+ 1 day
I know for another table the users that are targeted for each campaign, I just want to keep for more than 'today' the count of users that took the offer that was given to them.
You can GROUP BY dates and use SUM the find how many users eligible for campaigns and use CASE to do your conditions. And bonus is MIN to find which specific user related with the condition is only one user match.
CREATE TABLE Campain
(
UserId INT
,EligibleForOffer BIT
,BoughtToday BIT
,Timestamp DATE
)
INSERT INTO Campain
VALUES
(1,0,0,'2018-11-24')
,(1,1,0,'2018-11-25')
,(1,1,1,'2018-11-26')
,(1,0,0,'2018-11-27')
,(2,1,0,'2018-11-24')
,(2,1,1,'2018-11-25')
,(2,1,0,'2018-11-26')
,(2,0,1,'2018-11-27')
SELECT Timestamp
,SUM(CAST(EligibleForOffer AS INT)) NumberOfUsersTargeted
,CASE WHEN SUM(CAST(EligibleForOffer AS INT))=1 THEN 'UserId-'+CAST(MIN(UserId) AS VARCHAR) WHEN SUM(CAST(EligibleForOffer AS INT))>1 THEN 'Multiple Users(Both)' ELSE 'No Target' END UsersTargetedDetail
,SUM(CAST(BoughtToday AS INT)) NumberOfBought
,CASE WHEN SUM(CAST(BoughtToday AS INT))=1 THEN 'UserId-'+CAST(MIN(UserId) AS VARCHAR) WHEN SUM(CAST(BoughtToday AS INT))>1 THEN 'Multiple Users(Both)' ELSE 'No Buying' END BoughtDetail
FROM Campain
GROUP BY Timestamp

SQL - Query same column twice with different dates in where clause

I have tried searching all over for answers but none have answered my exact issue. I have what should be a relatively simple query. However, I am very new and still learning SQL.
I need to query two columns with different dates. I want to return rows with the current number of accounts and current outstanding balance and in the same query, return rows for the same columns with data 90 days prior. This way, we can see how much the number of accounts and balance increased over the past 90 days. Optimally, I am looking for results like this:
PropCode|PropCat|Accts|AcctBal|PriorAccts|PriorBal|
----------------------------------------------------
77 |Comm | 350 | 1,000| 275 | 750
Below is my starting query. I realize it's completely wrong but I have tried numerous different solution attempts but none seem to work for my specific problem. I included it to give an idea of my needs. The accts & AcctBal columns would contain the 1/31/14 data. The PriorAcct & PriorBal columns would contain the 10/31/13 data.
select
prop_code AS PropCode,
prop_cat,
COUNT(act_num) Accts,
SUM(act_bal) AcctBal,
(SELECT
COUNT(act_num)
FROM table1
where date = '10/31/13'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
)
AS PriorAccts,
(SELECT
SUM(act_bal)
FROM table1
where date = '10/31/13'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
)
AS PriorBal
from table1
where date = '01/31/14'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
group by prop_code, prop_cat
order by prop_cat
You can use a CASE with aggregates for this (at least in SQL Server, not sure about MySQL):
...
COUNT(CASE WHEN date='1/31/14' THEN act_num ELSE NULL END) as 'Accts'
,SUM(CASE WHEN date='1/31/14' THEN act_bal ELSE NULL END) as 'AcctBal'
,COUNT(CASE WHEN date='10/31/13' THEN act_num ELSE NULL END) as 'PriorAccts'
,SUM(CASE WHEN date='10/31/13' THEN act_bal ELSE NULL END) as 'PriorAcctBal'
....
WHERE Date IN ('1/31/14', '10/31/13')

SQL case giving inconsistent result

I am getting an inconsistent result from below two SQL queries.
Query1 : select (case when 'Abc' = null then 1 else 0 end) from dual
Query2 : select (case when ('Abc' <> null) then 1 else 0 end) from dual
Result for both queries same i.e
0
What's wrong am I missing some thing ?
NOTE : : I know I can use IS NULL and IS NOT NULL but my question is why result from above queries is inconsistent.
EDIT : Added from answer of #ppeterka.
select (case when null = null then 1 else 0 end) from dual
This returns 0 too. Null is not even equal to itself.
But then what does this return?
select (case when null <> null then 1 else 0 end) from dual
0 again
SQLFiddle link
Because NULL is unknown that is why the result is 0. When you want to compare a column or a value if it is null or not, use IS NULL or IS NOT NULL.
select (case when 'Abc' IS null then 1 else 0 end) from dual -- 0
select (case when ('Abc' IS NOT null) then 1 else 0 end) from dual -- 1
SQLFiddle Demo
The result of comparing anything to NULL, even itself, is always NULL(not TRUE or FALSE).
Searched CASE expression:
If no Boolean_expression evaluates to TRUE, the Database Engine returns the else_result_expression if an ELSE clause is specified, or a NULL value if no ELSE clause is specified.
In your case the result always will be 0, because 0 in ELSE clause
To add a bit of twist to this, try this out:
select (case when null = null then 1 else 0 end) from dual
This returns 0 too. Null is not even equal to itself.
But then what does this return?
select (case when null <> null then 1 else 0 end) from dual
This returns 0 again! Oh holy... It is not even not equal to itself, while it is not equal to itself... Quite a situation to grasp without getting insane...
Why to keep this all in mind? - one might ask
One example is indexing: in Oracle, indexes don't work the way one would expect them to work on NULL values where a column permits the use of that value. This means that given an index, if all the values (fields, functions on fields, etc) of a row that are included in the index are all NULL, that row won't be indexed in that given index. So this means that an index, that has only one value indexed (for example, a field directly), a null value would mean that row not to be included in the index.
To overcome this
it might be advisable to add an index with a distinct, exact value semantically representing the NULL meaning, like NVL(mynullcol,-1) on a column only containing positive integers to be able to query them quickly.
or you could add a constant value to form a "semi-multivalue" index, that indexes all rows, where one can be null, as the other is a constant. (create index idx_myindex on table(column_with_nulls,1); )
(This question and this article detail this subject in a bit more depth)
Another example is ordering...
select (case when null < null then 1 else 0 end) from dual;
select (case when null > null then 1 else 0 end) from dual;
Both 0. This is OK... We expected this by now... And what about this?
select (case when 'Abc' > null then 1 else 0 end) from dual;
select (case when null > 'Abc' then 1 else 0 end) from dual;
Uh-oh... Both 0 again. This might be an issue - how is ordering going to work?
select col_1 from
(select null as col_1 from dual)
union all (select 'Abc' as col_1 from dual)
union all (select null as col_1 from dual)
union all (select null as col_1 from dual)
order by col_1
This however consistently returns:
Abc
null
null
null
Using ... order by col_1 DESC returns:
null
null
null
Abc
So from this, on an empirical basis, it does seem that 'Abc' < null... However, as per the valuable comment of #ypercube:
the sort order can be set with the NULLS LAST and NULLS FIRST modifiers (at least in Oracle).
What you observe is the default sort order when the ORDER BY has no modifier
NULL is a twisted business, it is wise to steer away from it if it is possible... (And this is not only true for SQL, but for certain situations in OOP languages too.)
You can't use <> or = with nulls. You need to say
select (case when 'Abc' is null then 1 else 0 end) from dual
and
select (case when 'Abc' is not null then 1 else 0 ) from dual
It is not inconsistent.
if you have 2 objects A,B then it's one of the following three:
A equals B
A not equals B
you cannot compare A and B
It's like examining if (0/0 > 0) or (0/0 < 0) or (0/0 = 0). You just cannot compare them. every option is false
For your example: case checks if your argument is true
argument ('abc'=null) is not true, it's null
argument ('abc'<>null) is not true, it's null
The value NULL means the data value for the column is Unknown. A NULL is not synonymous with Zero, or zero length string or blank.
Anything you compare with NULL will result in Unknown (NULL).
Please check this to clear your doubts. To have the correct result, use IS NULL or IS Not NULL as you already know.

MySQL Query: count entries by status

I have a log table with following schema:
OperatorId - JobId - Status ( Good/Bad/Ugly )
Alex 6 Good
Alex 7 Good
James 6 Bad
Description: Whenever an operator works on a job, an entry is made along with Status. That's it.
Now I need a report like:
OperatorId - Good Count - Bad Count - Ugly Count
Alex 2 0 0
James 0 1 0
select operatorid,
sum(if(status="good",1,0)) as good,
sum(if(status="bad",1,0)) as bad,
sum(if(status="ugly",1,0)) as ugly
from table
group by operatorid
This is called a Pivot Table. It is done by setting a value 1 or 0 for each state and then summing them up:
SELECT
T.OperatorId,
SUM(T.GoodStat) AS Good,
SUM(T.BadStat) AS Bad,
SUM(T.UglyStat) AS Ugly
FROM
(
SELECT
CASE WHEN Status = 'Good' THEN 1 ELSE 0 END AS GoodStat,
CASE WHEN Status = 'Bad' THEN 1 ELSE 0 END AS BadStat,
CASE WHEN Status = 'Ugly' THEN 1 ELSE 0 END AS UglyStat,
OperatorId
FROM logTable T
)
GROUP BY T.OperatorId
If, like me, you prefer, whenever possible, to calculate counts with COUNT rather than with SUM, here's an alternative solution, which uses a method asked about in this thread:
SELECT
operatorid,
COUNT(status = 'good' OR NULL) as good,
COUNT(status = 'bad' OR NULL) as bad,
COUNT(status = 'ugly' OR NULL) as ugly
FROM table
GROUP BY operatorid