Stop MySQL from selecting empty rows in query - mysql

I am trying to write a script that will allow me to query my database and show the user even if the user has numerous profiles.
+----+-------+---------+--------------------+
| id | name | phone | email |
+----+-------+---------+--------------------+
| 1 | bob | 5555555 | bob#gmail.com |
| 2 | John | 6666666 | john#gmail.com |
| 3 | robert| 5555555 | bobswork#gmail.com |
+----+-------+---------+--------------------+
I am doing this currently with this query:
SELECT DISTINCT a.* FROM entires a INNER JOIN
(SELECT * FROM entires WHERE id='1') b
ON (a.phone=b.phone
OR a.email=b.email
);
Which works really well, however it breaks the whole system if two fields are blank. Then it just matches everything and I get the results of every entry with missing details. How can I prevent this from showing blank matches?

For mySql use IFNULL() function in join condition.
Ex: IFNULL(a.phone, '1111') = IFNULL(b.phone, '1111') or IFNULL(a.email, 'a#a.com') = IFNULL(b.email, 'a#a.com').
IFNULL() function takes the second argument value if the first argument is NULL. In above case condition will be true if both the records having NULL value or same value. In case you want the condition to fail if both values are NULL, then take different value in second argument for IFNULL() function.

Related

MySQL Inner Join with No Rows

I have a MySQL database that I normalized and the idea is to allow for a business to select zero or more marketing sequences, but the kicker is that a handful of marketing sequences are required (right now I have 4, but the list can grow). So what I've done is structured my tables as such:
sequence
+-------------+------------------+-------+-------------+----------+
| sequence_id | customer_type_id | title | description | required |
| 1 | 1 | ... | ... | true |
| 2 | 1 | ... | ... | true |
| 3 | 1 | ... | ... | false |
| 4 | 2 | ... | ... | true |
| 5 | 3 | ... | ... | true |
| 6 | 4 | ... | ... | false |
+-------------+------------------+-------+-------------+----------+
business_sequence
+----------------------+-------------+-------------+
| business_sequence_id | business_id | sequence_id |
+----------------------+-------------+-------------+
customer_type_id and business_id are foreign key fields that link to tables that describe the type of customer (customer, former customer, etc.) and the business's information (name, address, etc.) respectively.
The reason why I have the required column in my sequence table is so that if a business decides not to allow for any of the non-required sequences, then that business would not need a row. After all, there's no need to have duplicate rows in the business_sequence table if the only piece of data that is different is the business_id field.
Now what I'm trying to do is get all the rows and all the fields from the sequence table where the business_id in the business_sequence table matches a parameterized value (say 1 for the example that I'm going to show in a second). The query that I tried to use is:
SELECT
s.*
FROM
`sequence` AS s
INNER JOIN `business_sequence` AS b ON b.`sequence_id` = s.`sequence_id`
WHERE
b.`business_id` = 1 AND
s.`required` = true;
But this returned no results if the business had no rows in the sequence table. What I expected it to do is return the 0 rows from the b.business_id = 1 but I also expected it to return the 4 "required" rows (ids: 1, 2, 4, and 5) from the s.required = true.
Whenever I took out the INNER JOIN statement and the business_id portion of the WHERE clause, it does in fact return the 4 "required" rows. This leads me to believe that in my original query, because there are no rows for that particular business_id in the sequence table it isn't returning anything.
With all of this being said, how do I accomplish retrieving the zero or more rows when the business_id field matches the parameterized value and retrieve all of the rows when the required field is true?
How about using OR condition in stead of AND ?
SELECT
s.*
FROM
`sequence` AS s
INNER JOIN `business_sequence` AS b ON b.`sequence_id` = s.`sequence_id`
WHERE
b.`business_id` = 1 OR
s.`required` = true;
I was able to resolve my problem by performing a UNION as such:
SELECT * FROM `sequence` WHERE `required` = true
UNION
SELECT
s.*
FROM
`sequence` AS s
INNER JOIN `business_sequence` AS b ON b.`sequence_id` = s.`sequence_id`
WHERE
b.`business_id` = 1

How do I use COALESCE and JOIN at the same time and including NULL values in MySQL?

I'm having trouble using COALESCE and JOIN at the same time. My plan is:
to match the venture column from my current table against the vid column from venture list table and return the corresponding venture name.
if the venture column on the current table is zero (0) or null, the other column next to it will be selected ("venture_other" column)
Although my query returns its proper values, it seems like NULL values are ignored in this case.
venture_list table:
-------------------
| vid | name |
-------------------
| 1 | Malaysia |
-------------------
| 2 | Singapore |
-------------------
request_forms:
---------------------------------------------
| fid | username | venture | venture_other |
---------------------------------------------
| 1 | jake.long | 2 | |
---------------------------------------------
| 2 | xander.f | 0 | Japan |
---------------------------------------------
Expected Result
---------------
| venturename |
---------------
| Singapore |
---------------
| Japan |
---------------
Actual Result
---------------
| venturename |
---------------
| Singapore |
---------------
Here's my query:
SELECT COALESCE(NULLIF(ventures.name, null), venture_other) AS venturename
FROM request_forms forms
JOIN venture_list ventures ON ventures.vid = forms.venture
I tried rearranging the column names, but didn't work.
The problem is that MySQL default behaviour on a JOIN is an INNER JOIN.
Obviously since there is no matching result for the second row in venture_list you only get 1 row back.
Try using LEFT JOIN THAT way the column ventures.name will result in NULL and thus venture_other will be used.
Your original use of NULLIF() here is peculiar. From the documentation:
Returns NULL if expr1 = expr2 is true, otherwise returns expr1.
So your statement said, "In the event that ventures.name is NULL then return NULL else return ventures.name". Which is superfluous since a NULL will already return a NULL because it's NULL.
Instead of the case, and properly using the NULLIF() you could have the NULLIF() return a NULL in the event that ventures.name is 0:
SELECT COALESCE(NULLIF(ventures.name, 0), venture_other) AS venturename
FROM request_forms forms
JOIN venture_list ventures ON ventures.vid = forms.venture
You were pretty close but need to change the nullif a bit:
select coalesce(nullif(ventures.name,0), venture_other) as venturename
from request_forms forms
join venture_list ventures
on ventures.vid = forms.venture;
Basically, you want to use nullif to null out ventures.name if it is 0..then the coalesce does the rest.

Add user defined value to a column in an sql query

I have an SQL query:
select DISTINCT shortname_chn from dim_channel;
The query returns me data for example:
| shortname_chn (VARCHAR) |
|__________________________|
| MTV |
| National Geographic|
| Discovery |
| ARY News |
How can I manipulate the SQL query so that I can add an additional row to the returned rows.
Following is the result I wish to get after running some query:
| shortname_chn (VARCHAR) |
|__________________________|
| MTV |
| National Geographic|
| Discovery |
| ARY News |
| ALL |
Where the last row "ALL" is user defined, not present in the database.
In the above mentioned regard, I researched and came across this question : How to add a user defined column with a single value to a SQL query but it targets the problem of adding a whole new column.
select DISTINCT shortname_chn from dim_channel
UNION
SELECT 'ALL'
You can simply do something like this by UNIONing with a query that returns your fake row, e.g.:
SELECT DISTINCT
shortname_chn
FROM dim_channel
UNION ALL
SELECT 'ALL' AS shortname_chn

mysql returns wrong results with random duplicate values

i need to return the best 5 scores in each category from a table.so far i have tried query below following an example from this site: selecting top n records per group
query:
select
subject_name,substring_index(substring_index
(group_concat(exams_scores.admission_no order by exams_scores.score desc),',',value),',',-1) as names,
substring_index(substring_index(group_concat(score order by score desc),',',value),',',-1)
as orderedscore
from exams_scores,students,subjects,tinyint_asc
where tinyint_asc.value >=1 and tinyint_asc.value <=5 and exam_id=2
and exams_scores.admission_no=students.admission_no and students.form_id=1 and
exams_scores.subject_code=subjects.subject_code group by exams_scores.subject_code,value;
i get the top n as i need but my problem is that its returning duplicates at random which i dont know where they are coming from
As you can see English and Math have duplicates which should not be there
+------------------+-------+--------------+
| subject_name | names | orderedscore |
+------------------+-------+--------------+
| English | 1500 | 100 |
| English | 1500 | 100 |
| English | 2491 | 100 |
| English | 1501 | 99 |
| English | 1111 | 99 |
|Mathematics | 1004 | 100 |
| Mathematics | 1004 | 100 |
| Mathematics | 2722 | 99 |
| Mathematics | 2734 | 99 |
| Mathematics | 2712 | 99 |
+-----------------------------------------+
I have checked table and no duplicates exist
to confirm there are no duplicates in the table:
select * from exams_scores
having(exam_id=2) and (subject_code=121) and (admission_no=1004);
result :
+------+--------------+---------+--------------+-------+
| id | admission_no | exam_id | subject_code | score |
+------+--------------+---------+--------------+-------+
| 4919 | 1004 | 2 | 121 | 100 |
+------+--------------+---------+--------------+-------+
1 row in set (0.00 sec)
same result for English.
If i run the query like 5 times i sometimes end up with another field having duplicate values.
can anyone tell me why my query is behaving this way..i tried adding distinct inside
group_concat(ditinct(exams_scores.admission_no))
but that didnt work ??
You're grouping by exams_scores.subject_code, value. If you add them to your selected columns (...as orderedscore, exams_scores.subject_code, value from...), you should see that all rows are distinct with respect to these two columns you grouped by. Which is the correct semantics of GROUP BY.
Edit, to clarify:
First, the SQL server removes some rows according to your WHERE clause.
Afterwards, it groups the remaining rows according to your GROUP BY clause.
Finally, it selects the colums you specified, either by directly returning a column's value or performing a GROUP_CONCAT on some of the columns and returning their accumulated value.
If you select columns not included in the GROUP BY clause, the returned results for these columns are arbitrary, since the SQL server reduces all rows equal with respect to the columns specified in the GROUP BY clause to one single row - as for the remaining columns, the results are pretty much undefined (hence the "randomness" you're experiencing), because - what should the server choose as a value for this column? It can only pick one randomly from all the reduced rows.
In fact, some SQL servers won't perform such a query and return an SQL error, since the result for those columns would be undefined, which is something you don't want to have in general. With these servers (I believe MSSQL is one of them), you more or less can only have columns in you SELECT clause which are part of your GROUP BY clause.
Edit 2: Which, finally, means that you have to refine your GROUP BY clause to obtain the grouping that you want.

MySQL - COUNT before INSERT in one query

Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...