Count twice if certain condition satisfies in mysql - mysql

I have a scenario where I need to display total number of attendees of an event. With the help of registration form I have already captured the details of people who are attending and my table looks like below.
ID | NAME | PHONE_NUMBER | IS_LIFE_PARTNER_ATTENDING
1 | ABC | 1234567890 | N
2 | PQR | 1234567891 | Y
3 | XYZ | 1234567892 | N
I can easily display number of registrations by using count(id). But while displaying number of attendees I have to consider as two attendees if registrant is coming with his/her partner. (identified by IS_LIFE_PARTNER_ATTEDNING column)
So, in the above case, the number of registrants are 3, but number of attendees are 4, because "PQR" is coming with his/her life partner.
How can we do this in mysql query?

You can use the following query:
SELECT
SUM( 1 + (IS_LIFE_PARTNER_ATTEDNING = 'Y')) AS totalAttendees
FROM your_table;
WORKING DEMO
Since boolean expression resolves into 0/1 in MySQL so that you can capitalize this in your case.
Note:
SUM(a=b) returns 1 only if a is equal to b otherwise it returns 0
Caution:
*Never underestimate these parentheses (IS_LIFE_PARTNER_ATTEDNING = 'Y'). If you omit them then the whole summation would result in zero(0).
* because of operator precedence

Use SUM with CASE
SELECT
Name,
SUM(CASE WHEN IS_LIFE_PARTNER_ATTEDNING='y' THEN 2 ELSE 1 END ) AS'Attendes'
FROM
table
GROUP by name

Related

matching percentage with mysql

I have been trying to create an algorithm with MySQL that returns a list of users that matches an offer and the percentage of the matching. If the users matches the basic main criteria of the offer, they got 70% as a start then if they match some secondary criteria the matching percentage adds up by 2%.
I still don't know how to do it, if you have any idea please enlighten me. Thank you in advance
1. | User | | Offer |
2. |:--------| |:---------|
3. | city | | city-lis |
4. | age | | age-min |
5. | gender | | gender |
List item
if those criteria meets those users should get 70% as matching percentage than if they meet other criteria the percentage goes up
From what I can deduce from your question, this bit of pseudocode might help:
SELECT username,
68 +
((SELECT city = "example")*2) +
((SELECT gender = "m")*2) +
((SELECT age > 21)*2) AS score
FROM users
WHERE city = "example" OR gender="m" OR age > 21;
Explanation
I first select users that match any of the criteria, then I generate a score using subqueries. The (SELECT gender = "m") type subqueries will result in 1 if they are true (IE: if gender is m). I then multiply that by 2 to get the preferred score of '2'. If gender does not match 'm' the result will be 0. And 0 * 2 = 0. I start out with a score of 68 because you mentioned a starting score of 70 if any field matched. Because all rows in this result will match at least one of these, I substracted 2.
In MySQL you can use SELECT without defining a table to select from. The query SELECT 1+1 will result in 2. When you use these as subquery you can use the fields in the result for all kinds of tricks. I used them to generate a 1 or 0 for my score result.

MySQL: Is UNION what I am looking for? (break row up into multiple row return)

I have a table with the following columns:
id
first
last
institution
address
space1_1_value
space1_2_value
space2_1_value
space2_2_value
space3_1_value
space3_2_value
agreement
** trimmed down field count for example sake. **
In the end, I want to export my query to a spreadsheet, but I cant seem to get a nice working query. (hence the post)
While one record/row in the table will have value(s) for id, first, last, institution, address, space1_1_value, space1_2_value and agreement fields/cols...
it may or may not have values for the cols:
space2_1_value
space2_2_value
and
space3_1_value
space3_2_value
I'm not sure to explain it.. but more or less,.. I want to break up each record/row in the table to 1-3 'rows' (for lack of a better explanation)
So for EACH ROW/RECORD in the table..
I want to return the following:
id | first | last | institution | address | space1_1_value |
space1_2_value | agreement
if there are value in space2_1_value then:
id | first | last | institution | address | space2_1_value |
space2_2_value | agreement
if there are value in space3_1_value then:
id | first | last | institution | address | space3_1_value |
space3_2_value | agreement
To summarize.. EACH record has all the initial cols listed above. I am trying to 'break up' the return for each row by 'spaceX_X_value' groups.. if not empty.
Reading here:
http://www.mysqltutorial.org/sql-union-mysql.aspx
it says to use UNION for vertically appending results..
but I havent been able to get anything worth while working.
failed attempt (seems to bloated)... I feel like I can specifically select the 'static/commons' fields in each desired row/result, and UNION/SELECT the different spaceX_Xvalue groups.
SELECT * FROM
(
(SELECT first, last, space2_value FROM report WHERE space2_value <> '')
UNION
(SELECT first, last, space3_value FROM report WHERE space3_value <> '')
) AS results
EDIT/UPDATE:
From the comments below...this is a working example: (just feels a bit redundant typing out the same cols names like first, last..etc for each select)
SELECT first, last, space1_value as space_value FROM report
UNION
SELECT first, last, space2_value as space_value FROM report WHERE space2_value <> ''
UNION
SELECT first, last, space3_value as space_value FROM report WHERE space3_value <> ''
ORDER BY first
Consider using UNION ALL if you don't want duplicate rows to be automatically removed.
From MySQL documentation :
The default behavior for UNION is that duplicate rows are removed from the result. The optional DISTINCT keyword has no effect other than the default because it also specifies duplicate-row removal. With the optional ALL keyword, duplicate-row removal does not occur and the result includes all matching rows from all the SELECT statements.
SELECT first, last, space2_value as space_value FROM report WHERE space2_value <> ''
UNION
SELECT first, last, space3_value as space_value FROM report WHERE space3_value <> ''
Column names must be equal in every query for UINION
Use unpivot to make columns into rows:
Data: I created a table called yourtable and populated with some data:
id first last institution address space1_1_value space1_2_value space2_1_value space2_2_value space3_1_value space3_2_value agreement
----------- ---------- ---------- ----------- -------------------- -------------- -------------- -------------- -------------- -------------- -------------- --------------------
1 oliver koo mac 123 street 1 1 2 3 3 5 agree
2 mr.derp herp carl sesame street 7 7 NULL 1 4 9 disagree
Query: then I executed this query including tow unpivot relational operators:
SELECT id,first, last, institution, address, spacex_1_value , spacex_2_value
from yourtable
unpivot
(spacex_1_value for x1 in
(space1_1_value, space2_1_value,space3_1_value)
) unpvt1
unpivot
(
spacex_2_value for x2 in
(space1_2_value, space2_2_value,space3_2_value)
) unpvt2
WHERE SUBSTRING(x1,6,1) = SUBSTRING(x2,6,1)
Result:
id first last institution address spacex_1_value spacex_2_value
----------- ---------- ---------- ----------- -------------------- -------------- --------------
1 oliver koo mac 123 street 1 1
1 oliver koo mac 123 street 2 3
1 oliver koo mac 123 street 3 5
2 mr.derp herp carl sesame street 7 7
2 mr.derp herp carl sesame street 4 9
note: the where clause is crucial on joining the x1 (not selected) and x2 (not selected) columns. Without it, we haven't told SQL Server how the second set of unpivoted data matches the first. SQL would do a cross join. So the where clause is necessary to filter out unwanted rows.
hope this helps

MySQL counting number of max groups

I asked a similar question earlier today, but I've run into another issue that I need assistance with.
I have a logging system that scans a server and catalogs every user that's online at that given moment. Here is how my table looks like:
-----------------
| ab_logs |
-----------------
| id |
| scan_id |
| found_user |
-----------------
id is an autoincrementing primary key. Has no real value other than that.
scan_id is an integer that is incremented after each successful scan of all users. It so I can separate results from different scans.
found_user. Stores which user was found online during the scan.
The above will generate a table that could look like this:
id | scan_id | found_user
----------------------------
1 | 1 | Nick
2 | 2 | Nick
3 | 2 | John
4 | 3 | John
So on the first scan the system found only Nick online. On the 2nd it found both Nick and John. On the 3rd only John was still online.
My problem is that I want to get the total amount of unique users connected to the server at the time of each scan. In other words, I want the aggregate number of users that have connected at each scan. Think counter.
From the example above, the result I want from the sql is:
1
2
2
EDIT:
This is what I have tried so far, but it's wrong:
SELECT COUNT(DISTINCT(found_user)) FROM ab_logs WHERE DATE(timestamp) = CURDATE() GROUP BY scan_id
What I tried returns this:
1
2
1
The code below should give you the results you are looking for
select s.scan_id, count(*) from
(select distinct
t.scan_id
,t1.found_user
from
tblScans t
inner join tblScans t1 on t.scan_id >= t1.scan_id) s
group by
s.scan_id;
Here is sqlFiddle
It assumes the names are unique and includes current and every previous scans in the count
Try with group by clause:
SELECT scan_id, count(*)
FROM mytable
GROUP BY scan_id

MySQL pull data from same table, SUM multiple columns with conditions

I have created a users table that holds names and phone numbers (users).
id| name | phone
1 | Frank | 0345221234
2 | Sara | 0342555939
I got another table that holds a log with user's calls to different numbers (call_logs):
number | destination | price
0345221234 | destination | x /// This is Frank
0345221234 | destination | y /// This is also Frank
0342555939 | destination | z /// This is Sara
And then I have a table that holds numbers that Frank and Sara are allowed to call (allowed_numbers):
number
033485733
045727728
082358288
I would like to loop through my users table and based on their number to check the calls log table and select the SUM of price column for log records where destination does not match the allowed numbers table so that I know the cost for calls not in the allowed list.
Then I want to select SUM of price column for log records where destination DO match
the allowed numbers table so that I know how much did the allowed calls cost.
Is there any way I can do this in a single query with sub-queries and all needed in order to achieve this result set:
users number | SUM(price) of allowed calls | SUM(price) of calls not allowed
Thank you!
SELECT call_logs.number
,SUM(IF(allowed_numbers.number IS NOT NULL,call_logs.price,0)) AS AllowedPrice
,SUM(IF(allowed_numbers.number IS NULL,call_logs.price,0)) AS NotAllowedPrice
FROM call_logs
LEFT JOIN allowed_numbers
ON call_logs.destination = allowed_numbers.number
GROUP BY call_logs.number;

How to select a MAX record based on multiple results from a unique ID in MySQL

I run a report in mysql which returns all active members and their associated plan selections. If a member is terminated, this is displayed on the report as well. The issue I am facing, however is when a member simply decides to 'change' plans. Our system effective 'terminates' the original plan and starts fresh with the new one while keeping the original enrollment information for the member.
Sample report data may look like the following:
MemberID | Last | First | Plan Code | Original Effective | Change Date | Term Date
--------------------------------------------------------------------------------------------
12345 | Smith | John | A | 05-01-2011 | | 06-01-2011
12345 | Smith | John | B | 06-01-2011 | |
In the example above, a member had plan code A from May 1, 2011 to June 1, 2011. On June 1, 2011, the member changed his coverage to Plan B (and is still active since no term or change data).
Ultimately, I need my report to generate the following instead of the 2 line items above:
MemberID | Last | First | Plan Code | Original Effective | Change Date | Term Date
--------------------------------------------------------------------------------------------
12345 | Smith | John | B | 05-01-2011 | 06-01-2011 |
which shows his original plan effective date, the date of the change, and leaves the termination field blank.
I know I can get into a single row by using Group By the Member ID and I can even add the change date into the appropriate field with a (IF COUNT() > 1) statement but I am not able to figure out how to show the correct plan code (C) or how to leave the term date blank keeping the original effective date.
Any ideas?
Although I hate columns with embedded spaces and having to tick them, this should do it for you. The PreQuery will detect how many policy entries there are, preserve the first and last too, grouped by member. Once THAT is done, it can re-join the the plan enrollment on the same member but matching ONLY for the last "Original Effective" date for the person... That will give you the correct Plan Code. Additionally, if the person was terminated, it's date would be filled in for you. If still employed, it will be blank on that record.
select STRAIGHT_JOIN
pe2.MemberID,
pe2.Last,
pe2.First,
pe2.`Plan Code`
PreQuery.PlanStarted `Original Effective`,
case when PreQuery.PlanEntries > 1 then PreQuery.LastChange end `Change Date`,
pe2.`Term Date`
from
( select
pe.MemberID,
count(*) as PlanEntries,
min( `pe`.`Original Effective` ) PlanStarted,
max( `pe`.`Original Effective`) LastChange
from
PlanEnrollment pe
group by
pe.MemberID ) PreQuery
join PlanEnrollment pe2
on PreQuery.MemberID = pe2.MemberID
AND PreQuery.LastChange = pe2.`Original Effective`
I remember having the problem, but not coming up with a GROUP BY-based solution ;)
Instead, I think you can do something like
SELECT memberid, plancode
FROM members
INNER JOIN plans ON members.id=plans.member_id
WHERE plans.id IN
(SELECT id FROM plans
WHERE member_id = members.id
ORDER BY date DESC
LIMIT 0,1)