SQL select default value when there is no such value - mysql

I have following tables in DB.
ACCOUNT TABLE
User_id| first_name | last_name | age |
_______|_____________|____________|_________|
1 | LeBron | James | 28 |
2 | Kobe | Bryent | 29 |
3 | Kevin | Durant | 30 |
4 | Jim | Jones | 31 |
5 | Paul | Pierce | 32 |
6 | Jeremy | Lin | 33 |
USER_BOOKMARK TABLE
User_id| Bookmarked_user_id
_______|____________________
1 | 2
1 | 3
1 | 4
2 | 1
2 | 4
3 | 1
5 | 6
I want to select user's information from ACCOUNT table and also whether that person is in my Bookmark list
ex) Lebron James wants to know Jeremy Lin's information and whether Jeremy is in he's bookmark lists.
Desired results =>
User_id| first_name | last_name | age | isBookmarked |
_______|_____________|____________|_________|______________|
6 | Jeremy | Lin | 33 | 0 | =>0 means no.
*It must return only one row.
*If user is on my bookmark list, value of isBookmarked is my user_id.
What I tried =>
SELECT ACCOUNT.user_id, ACCOUNT.firstname, ACCOUNT.lastname, coalesce(User_Bookmark.user_id, 0) as isBookmarked
FROM Account LEFT OUTER JOIN User_Bookmark ON Account.user_id = User_Bookmark.Bookmarked_user_id
WHERE Account.user_id=6 AND User_Bookmark.user_id=1
But this query returns zero rows... since I'm not an expert on sql, I assume that I'm missing something. Can anyone help me?

The User_Bookmark.user_id = 1 test is filtering out the non-matching rows, because that column will be NULL when there's no match. When doing a LEFT JOIN, you have to put conditions on the second table into the ON clause rather than WHEN.
SELECT ACCOUNT.user_id, ACCOUNT.firstname, ACCOUNT.lastname, coalesce(User_Bookmark.user_id, 0) as isBookmarked
FROM Account
LEFT OUTER JOIN User_Bookmark
ON Account.user_id = User_Bookmark.Bookmarked_user_id AND User_Bookmark.user_id=1
WHERE Account.user_id=6

Related

Mysql - Compare int field with comma separated field from another table

I have two tables in a MySQL database like this:
User:
userid |userid | Username | Plan(VARCHAR) | Status |
-----------+------------+--------------+---------------+---------+
1 | 1 | John | 1,2,3 |1 |
2 | 2 | Cynthia | 1,2 |1 |
3 | 3 | Charles | 2,3,4 |1 |
Plan: (planid is primary key)
planid(INT) | Plan_Name | Cost | status |
-------------+----------------+----------+--------------+
1 | Tamil Pack | 100 | ACTIVE |
2 | English Pack | 100 | ACTIVE |
3 | SportsPack | 100 | ACTIVE |
4 | KidsPack | 100 | ACTIVE |
OUTPUT
id |userid | Username | Plan | Planname |
---+-------+----------+------------+-------------------------------------+
1 | 1 | John | 1,2,3 |Tamil Pack,English Pack,SportsPack |
2 | 2 | Cynthia | 1,2 |Tamil Pack,English Pack |
3 | 3 | Charles | 2,3,4 |English Pack,Sportspack, Kidspack |
Since plan id in Plan table is integer and the user can hold many plans, its stored as comma separated as varchar, so when i try with IN condition its not working.
SELECT * FROM plan WHERE find_in_set(plan_id,(select user.planid from user where user.userid=1))
This get me the 3 rows from plan table but i want the desired output as above.
How to do that.? any help Please
A rewrite off your query what should work is as follows..
Query
SELECT
all columns you need
, GROUP_CONCAT(Plan.Plan_Name ORDER BY Plan.planid) AS Planname
FROM
Plan
WHERE
FIND_IN_SET(Plan.plan_id,(
SELECT
User.Plan
FROM
user
WHERE User.userid = 1
)
)
GROUP BY
all columns what are in the select (NOT the GROUP_CONCAT function)
You also can use FIND_IN_SET on the ON clause off a INNER JOIN.
One problem is that the join won't ever use indexes.
Query
SELECT
all columns you need
, GROUP_CONCAT(Plan.Plan_Name ORDER BY Plan.planid) AS Planname
FROM
User
INNER JOIN
Plan
ON
FIND_IN_SET(Plan.id, User.Plan)
WHERE
User.id = 1
GROUP BY
all columns what are in the select (NOT the GROUP_CONCAT function)
Like i said in the comments you should normalize the table structures and add the table User_Plan whats holds the relations between the table User and Plan.

How to make IN condition check for set values

Basically I have two tables
MY_CHARACTER:
_________________________________________________
| char_ID | char_name | char_class | char_rank |
|------------------------------------------------|
| 1 | Aragorn | Fighter | 99 |
| 2 | Legolas | Archer | 90 |
| 3 | Smeagle | Spy | 20 |
|________________________________________________|
and
EQUIPMENT:
_________________________________________________
| equip_ID | equip_name | equip_owner | required |
|--------------------------------------------------|
| 1 | The one ring | 3 | 99 |
| 2 | Longsword | 1 | 90 |
| 3 | Waistcloth | 3 | 10 |
| 4 | Nazguls Mask | 2 | 95 |
|__________________________________________________|
Now what I want is to make a select command using IN condition, which will give me list of equipments that the characters are not eligible to use. So in this very example, it would be Smeagle being ineligible to wear the one ring and Legolas unable to wield the nazguls mask.
My command looks something like this
SELECT equip_name, equip_owner, required
FROM EQUIPMENT WHERE required IN (SELECT char_rank MY_CHARACTER);
Now this will only print out the equipment where required=char_rank however i want to print out a select, where required equipment level is higher than char_rank instead. Any idea how? Ideally using the IN condition.
EDIT: To clear out confusion regarding where I want, basically what my command does right now is it checks if EQUIPMENT.required=MY_CHARACTER.char_rank what I want instead is that it checks EQUIPMENT.required>MY_CHARACTER.char_rank
I would do this with a join:
select c.*, equip_id as notEligible
from my_character c join
equipment e
on c.char_rank < e.required;
So if you want a list of items, that a certain character is not allowed to use you can slightly modify your SQL:
SELECT
equip_name, equip_owner, required
FROM
EQUIPMENT
WHERE
required > (SELECT char_rank FROM MY_CHARACTER WHERE char_id=?);

How to properly join two tables to use alternative ORDER BY

Two tables...
people (personid, name, mainordering)
entries (userid, personid, altordering)
"personid" is the common field. My app displays a draggable list users can move around. When done, they click to "lock" in their order.
Table : people
+----------+---------+--------------+
| personid | name | mainordering |
+----------+---------+--------------+
| 1 | Bob | 2 |
| 2 | Charlie | 4 |
| 3 | Jim | 1 |
| 4 | Doug | 3 |
+----------+---------+--------------+
So using mainordering, it would display:
Jim
Bob
Doug
Charlie
entries table might have (for user 16):
+--------+----------+-------------+
| userid | personid | altordering |
+--------+----------+-------------+
| 16 | 1 | 3 |
| 16 | 2 | 1 |
| 16 | 3 | 2 |
| 16 | 4 | 4 |
+--------+----------+-------------+
So if user 16 has already submitted his entry BUT NOT LOCKED IT IN, I want to display his list using altordering. i.e.
Charlie
Jim
Bob
Doug
I'm struggling with the proper join to use. Here is what I tried and isn't working (it's simply ordering by mainordering still)...
$sql = "SELECT * from entries
WHERE userid=".$_SESSION['userid']."
LEFT JOIN people ON entries.personid = people.personid
ORDER BY altordering";
Any thoughts would be much appreciated. Thank you...
Are you sure you don't get an error when using WHERE before JOIN?
It should work like this:
SELECT people.*
FROM people
JOIN entries ON entries.personid = people.personid
WHERE entries.userid={$_SESSION['userid']}
ORDER BY entries.altordering
I assume entries.personid will always have a matching person in people, so you should use an INNER JOIN. You would use FROM entries LEFT JOIN people if you wanted to retrieve altordering even for non-existing people.

MySQL Count within an IF

+-------------+--------------+----------+-------+
| ticketRefNo | nameOnTicket | boughtBy | event |
+-------------+--------------+----------+-------+
| 38 | J XXXXXXXXX | 2 | 13 |
| 39 | C YYYYYYY | 1 | 13 |
| 40 | M ZZZZZZZZZZ | 3 | 14 |
| 41 | C AAAAAAA | 3 | 15 |
| 42 | D BBBBBB | 3 | 16 |
| 43 | A CCCCC | 3 | 17 |
+-------------+--------------+----------+-------+
+-------------+------------------+--------------+---------------------+--------+
| ticketRefNo | cardNo | cardHolder | exp | issuer |
+-------------+------------------+--------------+---------------------+--------+
| 38 | 4444111133332222 | J McKenny | 2016-01-01 00:00:00 | BOS |
| 39 | 4434111133332222 | C Dempsey | 2016-04-01 00:00:00 | BOS |
| 40 | 4244111133332222 | M Gunn-Davis | 2018-02-01 00:00:00 | RBS |
+-------------+------------------+--------------+---------------------+--------+
+-------------+-------------+----------+
| ticketRefNo | boxOfficeID | paidWith |
+-------------+-------------+----------+
| 41 | 1 | card |
| 42 | 2 | cash |
| 43 | 3 | chequ |
+-------------+-------------+----------+
I have a database with the data shown above. It represents a ticket-buying system. I would like to be able to see a list of tickets bought with the name of the event and either the boxOfficeID or the issuer of the debit card.
I have tried running the following code, to no avail.
SELECT t.ticketRefNo AS 'Reference', t.event AS 'Event',
IF(COUNT(SELECT * FROM Online WHERE t.ticketRefNo=o.ticketRefNo;) >= 1,
o.issuer, InPerson.boxOfficeID) AS 'Card Issuer or Box Office'
FROM Ticket AS t, InPerson, Online AS o
WHERE t.ticketRefNo=o.ticketRefNo;
Cheers in advance!
Some notes: the semicolon character isn't valid syntax; if you have a need to delimit the subquery, wrap it in parens. Escape column aliases like you'd escape any other identifier: use backticks, not single quotes. Single quotes are used around string literals.
Assuming that issuer in the Online table is NOT NULL, and assuming that ticketRefNo is unique in both the Online and InPerson tables, you could do something like this:
SELECT t.ticketRefNo AS `Reference`
, t.event AS `Event`
, IF(o.ticketRefNo IS NOT NULL,o.issuer,i.boxOfficeId)
AS `Card Issuer or Box Office`
FROM Ticket t
LEFT
JOIN InPerson i
ON i.ticketRefNo = t.ticketRefNo
LEFT
JOIN Online o
ON o.ticketRefNo = t.ticketRefNo
Use outer join operations to find matching rows in the InPerson and Online tables, and use a conditional test to see if you got a matching row from the Online table. A NULL will be returned if there wasn't a matching row found.
It's not a good idea to have one column JOINing to two different tables with some values in each of the two tables.
But here goes anyway:
( SELECT ... FROM Ticket t JOIN InPerson x USING(ticketRefNo) ... )
UNION ALL
( SELECT ... FROM Ticket t JOIN Online x USING(ticketRefNo) ... )
ORDER BY ...
The ALL assumes that InPerson and Online never have any overlapping ticketRefNos.
The ORDER BY an the end is in case you want to sort things, although I see no need for it in your attempted SELECT.
The two SELECTs must have the same number of columns.

getting the count of distinct duplicate ids in mysql

this is the query
select count(*),
ss.pname,
ttu.user_id,
ttl.location_name ,
group_concat(em.customer_id),
count(em.customer_id)
from seseal as ss,
track_and_trace_user as ttu,
track_and_trace_location as ttl,
eseal_mapping as em
where ss.real_id=em.e_id
and em.user_id=ttu.user_id
and ttu.location_id=ttl.location_id
group by ss.pname, ttu.user_id, ttl.location_name
having count(em.customer_id)>1 ;
and following is the results:
+----------+----------------+---------+---------------+------------------------------+-----------------------+
| count(*) | pname | user_id | location_name | group_concat(em.customer_id) | count(em.customer_id) |
+----------+----------------+---------+---------------+------------------------------+-----------------------+
| 6 | Nokia N91 | 1 | Malad | 60,51,60,51,58,58 | 6 |
| 2 | SUPERIA 1000gm | 4 | Raichur | 51,46 | 2 |
| 5 | SUPERIA 1000gm | 5 | west bengal | 51,46,51,51,46 | 5 |
| 2 | SUPERIA 500gm | 4 | Raichur | 59,59 | 2 |
| 3 | SUPERIA 500gm | 5 | west bengal | 59,46,59 | 3 |
+----------+----------------+---------+---------------+------------------------------+-----------------------+
Now the problem is, as you can see in result set, the second last column in some rows the customer_ids are duplicate and in some rows are unique. And the last column is giving the count of it.
Now what i want is to pick the 3rd row, there are two customer ids namely 51 and 46 and these are duplicate in that row, so my last column for this row should contain 2.
Similarly for last row my last column should contain 1 as there is only one customer id which is duplicated i.e. 59.
So if you understand the exact problem then the 2nd row should not be part of this result set as it doesn't contain any customer ids that are duplicate.
How about:
group_concat(distinct em.customer_id)
and
count(distinct em.customer_id)