Want a null row where no data exist
Hello. This is in regards to MySQL Workbench 6.3.
I'm trying to return a list of results for every item listed in my select statement, which would include those items that don't actually exist. So if i list 5 items in my select statement and only 3 exist, i'd like to get 5 rows returned, 3 actual rows with data and 2 more rows that only show null. Can someone please show me how to edit my query below to show this ? Thank you !
select emails from table where email in (dog, frog, cat, tiger, lizard);
Actual Result (only the 3 emails that actual exist show)
dog
cat
tiger
Desired Result
dog
null
cat
tiger
null
The desired results are not possible.. You can't expect MySQL to
return the selected records in the order they went in the IN()
operator.
So i think you better off when you change the desired result to something you know sometiming was not found in the table, i think you are looking for.
Query
SELECT
search_emails.email
, (
CASE
WHEN t.email IS NOT NULL
THEN 'true' ELSE 'false'
END
) AS found
FROM (
SELECT 'dog' AS email
UNION
SELECT 'frog' AS email
UNION
SELECT 'cat' AS email
UNION
SELECT 'tiger' AS email
UNION
SELECT 'lizard' AS email
) AS search_emails
LEFT JOIN
t
ON
t.email = search_emails.email
Result
| email | found |
| ------ | ----- |
| dog | true |
| cat | true |
| tiger | true |
| frog | false |
| lizard | false |
see demo
select emails from table where email in (dog, frog, cat, tiger, lizard) OR email IS NULL
be sure that the values provided for IN (...) are provided as strings.
Related
I need help in merging rowns into column in sql:
Table:
|TopologyType | TopologyName | Name |
| 1 | oneway | client1 |
| 1 | oneway | client2 |
| 2 | proxy | client1 |
| 2 | proxy | proxy1 |
| 2 | proxy | client2 |
Output:
| 1 | oneway | client1 | NULL | client2 |
| 2 | proxy | client1 | proxy | client2 |
In case you don't need all of the output fields to be in columns you could use GROUP_CONCAT
Example query
SELECT `t`.`TopologyType`,`t`.`TopologyName`,GROUP_CONCAT(DISTINCT(`tt`.`Name`)) as `name` from `test` `t`
left join `test` `tt`
ON `t`.`TopologyType`=`tt`.`TopologyType`
GROUP BY `t`.`TopologyName`;
Output
TopologyType TopologyName name
1 oneway client1,client2
2 proxy client1,proxy1,client2
view this example in SQL fiddle
Oof, you're a bit ropey on detail so don't expect this answer to work without some adjustment. Let me present you some sample data:
Name, Class, Score
john, math, 70
james, math, 75
john, english, 48
james, english, 69
Desired output:
name, mathscore, englishscore
john, 70, 48
james, 75, 69
Pivoting query for mysql (doesn't support PIVOT command)
SELECT
name,
MAX(CASE WHEN class = 'math' THEN score END) as mathscore
MAX(CASE WHEN class = 'english' THEN score END) as englishscore
FROM
grades
GROUP BY
name
If you want to know more about how it works, then run it without the GROUP BY and without the MAX functions:
SELECT
name,
CASE WHEN class = 'math' THEN score END as mathscore
CASE WHEN class = 'english' THEN score END as englishscore
FROM
grades
And then bear in mind that MAX() will not consider nulls when doing its work, so it causes the rows to collapse to only those containing values
As an aside - see how i've phrased my answer in terms of giving a sample data and a desired output? Do please write your next SQL question more like that, including the SQL you tried
Edit:
OK, so just apply the pattern in my SQL, to your names. For me, the "name" was the fixed column, the "class" was the one being pivoted out into multiple columns. The general pattern is:
SELECT
fixedColumn1,
fixedColumn2
..
fixedColumnN,
MAX(CASE WHEN column_with_values_that_must_be_headers = a1_value_you_want_in_its_own_column THEN column_with_value_to_appear_as_data1) as column_header_name1,
MAX(CASE WHEN column_with_values_that_must_be_headers = a2_value_you_want_in_its_own_column THEN column_with_value_to_appear_as_data2) as column_header_name2,
...
MAX(CASE WHEN column_with_values_that_must_be_headers = aN_value_you_want_in_its_own_column THEN column_with_value_to_appear_as_dataN) as column_header_nameN
FROM
table
GROUP BY
fixedColumn1,
fixedColumn2
..
fixedColumnN,
Here's a partial; have a go at finishing it off - you'll learn way more about this technique put doing a bit of it, than just hanging around waiting for someone to give you the answer to paste in :)
SELECT
TopologyType,
TopologyName,
MAX(CASE WHEN name = 'client1' THEN name END) AS client1,
... --put more CASE WHENs here
FROM
table
GROUP BY
TopologyType,
TopologyName
The only slight difference between your query and my earlier examples is that I had one column that I wanted to be the header (the name of the class; english / maths) but another column to be the data (the test score of the person in that class) whereas you effectively want the name as the column header AND the data. It's ok though - just follow the pattern above, using the name column as the header and the data:
MAX(CASE WHEN name = 'client1' THEN name END) AS client1,
^^^^^^^^^^^^^^^^ ^^^^
column_header cell_data
I have two columns displaying the same type of information but not necessarily the same data. Although some of the data overlaps each column may/may not contain information that will also include NULL values. Like so:
Company ID | Company Name | Company ID | Company Name
-----------+--------------+------------+-------------
1 | A | 1 | A
2 | B | NULL | NULL
NULL | NULL | 3 | C
I am trying to merge columns 1 and 2 to columns 3 and 4, respectively, so that I have two columns that look like this:
Company ID | Company Name
-----------+-------------
1 | A
2 | B
3 | C
Looking at similar stackoverflow questions, I have doubt this may be done easily. Is this possible? Please, let me know!
Anything helps.
As you don't seem to be around to answer questions for clarification right now, let's go ahead.
It seems, you do actually have the four columns in question in a single table - but than, there should be no duplicate column names. Once they are unique, the following should work:
UPDATE SomeTable
SET company_ID_1 = IFNULL(company_ID_1, company_ID_2)
, company_Name_1 = IFNULL(company_Name_1, company_Name_2)
WHERE
company_ID_1 IS NULL
OR
company_Name_1 IS NULL
;
If the presented is actually the output of a join, you could replace the same by:
SELECT
IFNULL(SomeTable1.company_ID, SomeTable2.company_ID) company_ID
, IFNULL(SomeTable1.company_Name, SomeTable2.company_Name) company_Name
FROM SomeTable1
LEFT JOIN SomeTable2
ON SomeTable1.company_ID = SomeTable2.company_ID
UNION ALL
SELECT
IFNULL(SomeTable1.company_ID, SomeTable2.company_ID) company_ID
, IFNULL(SomeTable1.company_Name, SomeTable2.company_Name) company_Name
FROM SomeTable1
RIGHT JOIN SomeTable2
ON SomeTable1.company_ID = SomeTable2.company_ID
WHERE SomeTable1.company_ID IS NULL
ORDER BY company_ID
;
See it in action: SQL Fiddle
Please comment, if and as this requires adjustment / further detail.
For some reason, I am unable to export a table of subscribers from my phpList (ver. 3.0.6) admin pages. I've searched on the web, and several others have had this problem but no workarounds have been posted. As a workaround, I would like to query the mySQL database directly to retrieve a similar table of subscribers. But I need help with the SQL command. Note that I don't want to export or backup the mySQL database, I want to query it in the same way that the "export subscribers" button is supposed to do in the phpList admin pages.
In brief, I have two tables to query. The first table, user contains an ID and email for every subscriber. For example:
id | email
1 | e1#gmail.com
2 | e2#gmail.com
The second table, user_attribute contains a userid, attributeid, and value. Note in the example below that userid 1 has values for all three possible attributes, while userid's 2 and 3 are either missing one or more of the three attributeid's, or have blank values for some.
userid | attributeid | value
1 | 1 | 1
1 | 2 | 4
1 | 3 | 6
2 | 1 | 3
2 | 3 |
3 | 1 | 4
I would like to execute a SQL statement that would produce a row of output for each id/email that would look like this (using id 3 as an example):
id | email | attribute1 | attribute2 | attribute3
3 | e3#gmail.com | 4 | "" | "" |
Can someone suggest SQL query language that could accomplish this task?
A related query I would like to run is to find all id/email that do not have a value for attribute3. In the example above, this would be id's 2 and 3. Note that id 3 does not even have a blank value for attributeid3, it is simply missing.
Any help would be appreciated.
John
I know this is a very old post, but I just had to do the same thing. Here's the query I used. Note that you'll need to modify the query based on the custom attributes you have setup. You can see I had name, city and state as shown in the AS clauses below. You'll need to map those to the attribute id. Also, the state has a table of state names that I linked to. I excluded blacklisted (unsubscribed), more than 2 bounces and unconfirmed users.
SELECT
users.email,
(SELECT value
FROM `phplist_user_user_attribute` attrs
WHERE
attrs.userid = users.id and
attributeid=1
) AS name,
(SELECT value
FROM `phplist_user_user_attribute` attrs
WHERE
attrs.userid = users.id and
attributeid=3
) AS city,
(SELECT st.name
FROM `phplist_user_user_attribute` attrs
LEFT JOIN `phplist_listattr_state` st
ON attrs.value = st.id
WHERE
attrs.userid = users.id and
attributeid=4
) AS state
FROM
`phplist_user_user` users
WHERE
users.blacklisted=0 and
users.bouncecount<3 and
users.confirmed=1
;
I hope someone finds this helpful.
so im making a file hub nothing huge or fancy just to store some files that may be shared by others for download. and it just occured to me in the way that i originally intended to count the amount of upvotes or downvotes the query could be server heavy.the query to get the files is something along the lines of
select*from files;
and in such i would recieve an array of my files that i could loop over and get specifics on each file now with the inclusion of voting a file that same foreach loop would include a further query that would get the count the amount votes a file would get (the file id in the where clause) like so
select*from votes where upvoted=true and file.id=?
and i was thinking of using pdo::rowCount to get my answer. now evey bone in my body just says this is bad very bad as imagine im getting 10,000 files i just ran 10,000 extra queries one on each file and i havent looked at the downvotes yet which i was think could go in a similar fasion. any optimization adviece here is a small rep of the structure of a few tables. the upvoted and downvoted columbs are of type bool or tinyint if you will
table: file table: user table: votes
+----+-------------+ +----+-------------+ +--------+--------+--------+--------+
| id |storedname | | id | username | |file_id | user_id| upvoted | downvoted
+----+-------------+ +----+-------------+ +--------+--------+--------+--------+
| 1 | 45tfvb.txt | | 1 | matthew | | 1 | 2 | 1 | 0
| 2 |jj7fnfddf.pdf| | 2 | mark | | 2 | 1 | 1 | 1
| .. | .. | | .. | .. | | .. | .. | .. | ..
there are two ways to do this. the better way to do this (aka faster) is to write separate queries and build into one variable in your programming language (like php, python.. etc.)
SELECT
d.id as doc_id,
COUNT(v.document_id) as num_upvotes
FROM votes v
JOIN document d on d.id = v.document_id
WHERE v.upvoted IS TRUE
GROUP BY doc_id
);
that will return your list of upvoted documents. you can do the same for your downvotes.
then after your select from document do a for loop to compare the votes with the document by ID and build into a dictionary or list.
The second way to do this which can take a lot longer at runtime if you have a bunch of records in the table (its less efficient, but easier to write) is to add subquery selects in your select statement like this...
SELECT
logical_name ,
document.id ,
file_type ,
physical_name ,
uploader_notes ,
views ,
downloads ,
user.name ,
category.name AS category_name,
(Select count(1) from votes where upvoted=true and document_id=document.id )as upvoted,
(select count(1) from votes where upvoted=false and document_id=document.id) as downvoted
FROM document
INNER JOIN category ON document.category_id = category.id
INNER JOIN user ON document.uploader_id = user.id
ORDER BY category.id
Two advices:
Avoid SELECT * especially if you're going to count. Replace it, with something like that:
SELECT COUNT(1) AS total WHERE upvoted=true AND file.id=?
Maybe you want to create a TRIGGER to keep update a counter in the file table.
I hope it will be helpfull to you.
I have two tables, "records", and "info".
The "records" table looks like:
mysql> SELECT * FROM records WHERE num = '7';
+-----+--------+----+------+-----+-----+------------+-----------+----------+---------------------+
| id | city | st | type | num | val | startdate | status | comments | updated |
+-----+--------+----+------+-----+-----+------------+-----------+----------+---------------------+
| 124 | Encino | CA | AAA | 7 | 1 | 1993-09-01 | allocated | | 2014-02-26 08:16:07 |
+-----+--------+----+------+-----+-----+------------+-----------+----------+---------------------+
and so on. Think of the "num" field in this table as a Company ID.
The "info" table contains information about certain companies, and uses that company id as a unique identifier. Not all companies listed in "records" will be in "info". An example of the "info" table:
mysql> SELECT * FROM info LIMIT 2;
+-----+-------+--------------------------+---------------------+
| org | name | description | updated |
+-----+-------+--------------------------+---------------------+
| 0 | ACME | | 2014-02-19 10:35:39 |
| 1 | AT&T | Some Phone Company, Inc. | 2014-02-18 15:29:50 |
+-----+-------+--------------------------+---------------------+
So "org" here will match "num" in the first table.
I want to be able to run a query that returns, on one line, everything but 'id', 'type' and 'val' from the 1st table, and IF APPLICABLE, the 'name' and 'description' from the 2nd table.
I can achieve what I want using this query:
SELECT city,st,num,startdate,status,comments,updated, \
( SELECT name FROM info WHERE org = '7') AS name, \
( SELECT description FROM info WHERE org = '7') AS description \
FROM records WHERE num = '7'
But I see at least two problems with it:
It seems inefficient to run two subqueries
When there is no record in "info", NULL is printed for the name and
description. I would like to print some string instead.
To address the first problem, I tried to return an array. But when no corresponding record exists in the "info" table, then I get nothing, not even the valid info from the "records" table. Here's my array query:
SELECT city,st,num,startdate,status,comments,updated,asinfo.name AS name,asinfo.description AS description \
FROM records, \
( SELECT name,description FROM info WHERE org = '7') AS asinfo \
WHERE num = '7'
This query works fine if a given company id exists in both tables.
To address the second problem, I tried various incantations of IFNULL and coalesce, to no avail.
I'd appreciate any insight.
Thanks.
Apply LEFT JOIN syntax:
SELECT
r.city,
r.st,
r.num,
r.startdate,
r.status,
r.comments,
r.updated,
IF(d.name IS NULL, 'Default', d.name) AS name,
IF(d.description IS NULL, 'Default', d.description) AS description
FROM
records AS r
LEFT JOIN info AS d ON r.num=d.org
WHERE
r.num='7'
that will work such way: LEFT JOIN looks into first table, and, if there are no corresponding records in second, it applies NULL. So you'll discover that with IF (or IFNULL) and do substitution of default string.
Use a LEFT JOIN to get null values when there's no matching row in the info table.
SELECT city,st,num,startdate,status,comments,updated,
IFNULL(name, 'Default Name') name,
IFNULL(description, 'Default Description') description
FROM records r
LEFT JOIN info i ON r.num = i.org
WHERE r.num = 7
It sounds like a simple LEFT JOIN from record to info will do the trick.
LEFT JOIN rather than JOIN in order to ensure you ALWAYS get all rows from the record table, and then the corresponding data in info table if a xref exists for that ID.
Whether using your sub-queries or using joins, if you always want to see all rows in record table, then you will always get NULLs corresponding to the info table where no xref exists. The only way to avoid that is to run some code that calls everything from record, and then iterates over the results to query info, to conditionally add to the record data.