Retrieve all not logged in users from mysql tables (SQL query) - mysql

I have 2 tables listed below:
+-------------+-----------+--------------+-------------------------------+
| v3_customer |
+-------------+-----------+--------------+-------------------------------+
| customer_id | firstname | lastname | email |
+-------------+-----------+--------------+-------------------------------+
| 1 | Piet | Pizza | piet.pizza#example.com |
| 2 | Klaas | Hein | klaas.hein#example.com |
| 3 | Henk | Crowdcontrol | henk.crowdcontrol#example.com |
+-------------+-----------+--------------+-------------------------------+
+-------------+-------------+---------------+
| v3_customer_activity |
+-------------+-------------+---------------+
| activity_id | customer_id | key |
+-------------+-------------+---------------+
| 1 | 1 | login |
| 2 | 1 | order_account |
| 3 | 2 | login |
+-------------+-------------+---------------+
What i want is to select all customers which haven't logged in yet (note the login key in v3_customer_activity). So in this case that would be the customer with customer_id: 3
I'm using a mysql database.
I have tried using the following query:
SELECT DISTINCT v3_customer.customer_id, v3_customer.firstname, v3_customer.lastname, v3_customer.email FROM `v3_customer` JOIN v3_customer_activity ON v3_customer.customer_id = v3_customer_activity.customer_id WHERE v3_customer.customer_id != (SELECT v3_customer_activity.customer_id FROM v3_customer_activity)
In the hope it would iterate between the rows found in the subquery.
This resulted in an error telling me a subquery may not contain multiple rows.
TL;DR
What I want is to retrieve every customer from v3_customer who is not listed in the table v3_customer_activity

Try this:
select v3_customer.* from v3_customer
left join v3_customer_activity on v3_customer.customer_id=v3_customer_activity.customer_id
where v3_customer_activity.customer_id is null;
Left join v3_customer table with v3_customer_activity and filter records which are not matched.

select v3_customer.* from v3_customer
where v3_customer.customer_id not in (SELECT v3_customer_activity.customer_id FROM v3_customer_activity)

Related

Mysql count from multiple columns?

I have the following simplified tables:
statistics
+-------------+-------------+---------------+
| type | itemnumber | borrowernumber |
+-------------+-------------+---------------+
| issue | 26191 | 11978 |
+-------------+-------------+---------------+
| issue | 26190 | 11979 |
+-------------+-------------+---------------+
items:
+-------------+-------------+
| itemnumber | bibliono |
+-------------+-------------+
| 26191 | 27 |
+-------------+-------------+
| 26190 | 28 |
+-------------+-------------+
biblio_metadata:
+-------------+----------------------------------------------------+
| bibliono | metadata |
+-------------+----------------------------------------------------+
| 27 | <?xml.. <datafield tag="082" ind1="0" ind2="4"> |
| <subfield code="a">005.133/M29</subfield> |
| </datafield> |
+-------------+----------------------------------------------------+
| 28 | <?xml.. <datafield tag="082" ind1="0" ind2="4"> |
| <subfield code="a">995.133/M29</subfield> |
| </datafield> |
+-------------+----------------------------------------------------+
borrowers
+-------------+-------------+
| borrowerno | sort1 |
+-------------+-------------+
| 11978 | CAS |
+-------------+-------------+
| 11979 | CBA |
+-------------+-------------+
I want to get the following through a mysql query:
+-------------+------------+
| DDC Range | CAS | CBA |
+-------------+------------
| 001-100 | 1 | |
+-------------+------------
| 900-999 | | 1 |
+-------------+-----------+
I'm trying to find the right combination of queries - if it's mysql select query multiple columns or any other keyword but can't seem to get the right term to search.
I have the following made up mysql queries but can't go pass the first column 'CAS' and further query the other sort1's (in this example CBA).
SELECT CASE
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[0]{1}[0-9]{2}[^0-9]+.*' THEN "000-099"
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[9]{1}[0-9]{2}[^0-9]+.*' THEN "900-999"
ELSE "Others"
END as "DDC Range", count(borrowers.sort1)
from statistics s
LEFT JOIN items on (s.itemnumber=items.itemnumber)
LEFT JOIN biblio_metadata ON (items.biblionumber=biblio_metadata.biblionumber)
LEFT JOIN borrowers on (s.borrowernumber=borrowers.borrowernumber)
WHERE s.type = "issue"
AND borrowers.sort1="CAS"
GROUP BY Subjects
I'm looking into this COUNT(*) from multiple tables in MySQL but I don't know where to put the next query or if what I'm trying to arrive at is related to the aforementioned link. Thanks in advance
Looks like in your query you're filtering out all entries where borrowers.sort1="CAS" but if I understand correctly you'll need these.
Can't you just do all the joins as specified in your question and then use two case statements? As it seems you're interested in the count(*) per subject you can then sum them.
Maybe try something like below:
SELECT
CASE
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[0]{1}[0-9]{2}[^0-9]+.*' THEN "000-099"
WHEN ExtractValue(metadata, '//datafield[#tag="082"]/subfield[#code="a"]') REGEXP '^[9]{1}[0-9]{2}[^0-9]+.*' THEN "900-999"
ELSE "Others"
END as "DDC Range", count(borrowers.sort1),
sum(case when borrowers.sort1="CAS" then 1 else '' end) as 'CAS',
sum(case when borrowers.sort1="CBA" then 1 else '' end) as 'CBA'
from statistics s
LEFT JOIN items on (s.itemnumber=items.itemnumber)
LEFT JOIN biblio_metadata ON (items.biblionumber=biblio_metadata.biblionumber)
LEFT JOIN borrowers on (s.borrowernumber=borrowers.borrowernumber)
WHERE s.type = "issue"
GROUP BY Subjects

MySQL query to return a value if valus in two different rows match a condition

In the example below, I'm trying to create a query that returns the content of NAME if this contains both 'ammonium nitrate' and 'urea'. The thing is, they are in separate rows and I haven't found how to check for both. I've tried using the clauses IN, AND, and UNION, but to no avail.
The query should return only 'Gro-Fast', as it is the only NAME that contains both.
+-------+------------------+-------------+---------+
| FCODE | CNAME | NAME | CONTACT |
+-------+------------------+-------------+---------+
| 28994 | ammonium nitrate | Gro-Fast | 556698 |
| 28994 | urea | Gro-Fast | 556698 |
| 29462 | ammonium nitrate | BetterRoots | 342554 |
| 34588 | ammonium nitrate | Flourisher | 342554 |
| 83732 | urea | GreenAgain | 354211 |
+-------+------------------+-------------+---------+
TIA!
You can group by name and set the conditions in the HAVING clause:
select name
from tablename
where cname in ('ammonium nitrate', 'urea')
group by name
having count(distinct cname) = 2
If you want the column cnameto contain only 'ammonium nitrate' and 'urea':
select name
from tablename
group by name
having
sum(cname not in ('ammonium nitrate', 'urea')) = 0
and
count(distinct cname) = 2
See the demo.
Results:
> | name |
> | :------- |
> | Gro-Fast |
Edit, for your query:
select name
from CONTENTS natural join FERTILIZERS
where cname in ('ammonium nitrate', 'urea')
group by name
having count(distinct cname) = 2

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.

merger one row with null values to not null values of another row mysql

I want to merge two rows into one.The below format is in the database.
+----+---------+-----------------------+-------------------------+
| id | appid | photo | signature |
+====+=========+=======================+=========================+
| 1 | 10001 | 10001.photograph.jpg | NULL |
| 2 | 10001 | NULL | 10001.signature.jpg |
+----+---------+-----------------------+-------------------------+
I want a mysql query so that i can fetch data like below,
+--------+------------------------+-------------------------+
| appid | photo | signature |
+========+========================+=========================+
|10001 | 10001.photograph.jpg | 10001.signature.jpg |
+--------+------------------------+-------------------------+
Kindly suggest...
You can also use max function
select appid,
max(photo) photo,
max(signature) signature
from test
group by appid
Demo
This should do this:
select t1.appid,t1.photo,t2.signature from mytable t1 join mytable t2 on t1.appid=t2.appid where t1.id=1 and t2.id=2

SQL join several tables based on latest entry in transaction table per join record

I have a transaction table with timestamps
a transaction has one event and one user.
All transactions have an event,
All events have at least one trasaction,
Each transaction has a user that must exist,
A User will not necessarily have a transaction.
The output will be a sort of the evt list
Output line count should equal db.evt record count.
The first column of each table is the Autoinc unique index.
In transaction, these are fks to the other tables.
The problem is that I need the transaction with the latest timestamp for the evt in the transaction table.
I am still relatively new to SQL (Using MySQL) and while I muddle through joins. I have no idea how to get the latest record by evID by timestamp.
I have looked at other questions on the topic but not found one that addresses mine. (Granted there are 14K on Joins alone, so I may have missed one)
Sample Table Data below:
Table structure is hopefully obvious by I will edit it in if requested.
Edit:
I've changed the names of tables and columns for clarity (and to avoid matching keywords)
I tried Stuart's answer below and got an error:
Answer:
SELECT
eventTable.EvtName AS EvtD,
transTable.TranAct AS LastTrans,
userTable.UserName AS UsrNm
FROM
transTables,
INNER JOIN (
SELECT evtID, MAX(TransID) TransID FROM transTable GROUP BY evtID
) last ON last.evtID = transTable.evtID AND last.TransID = transTable.TransID
INNER JOIN eventTable ON eventTable.evtID = transTable.evtID
INNER JOIN userTable ON userTable.usId = transTable.usId
Response:
#1064 - You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near
'INNER JOIN (
SELECT evtID, MAX(TransID) TransID FROM transTable GROUP BY evt'
at line 7
Tables:
db.transTable
| TransID | EvtID | TranAct | timestamp | UserID
----------------------------------------------------------------
| 1 | 1 | add | 2014-05-08 08:10:00.000 | 3
| 2 | 2 | add | 2014-05-08 09:10:00.000 | 2
| 3 | 3 | add | 2014-05-08 10:10:00.000 | 3
| 4 | 2 | validate | 2014-05-08 11:10:00.000 | 5
| 5 | 3 | validate | 2014-05-08 12:10:00.000 | 3
| 6 | 2 | reverse | 2014-05-08 13:10:00.000 | 1
| 7 | 1 | edit | 2014-05-08 14:10:00.000 | 4
| 8 | 4 | add | 2014-05-08 15:10:00.000 | 3
| 9 | 5 | add | 2014-05-08 16:10:00.000 | 2
db.eventTable
| EvtID | EvtName
-----------------
| 1 | Evt1
| 2 | Evt2
| 3 | Evt3
| 4 | Evt4
| 5 | Evt5
db.userTable
| UserID | UserName
--------------------
| 1 | Usr1
| 2 | Usr2
| 3 | Usr3
| 4 | Usr4
| 5 | Usr5
Desired output:
eventTable.EvtName AS EvtD
transTable.TranAct AS LastTrans
userTable.UserName AS UsrNm
| EvtD | LastTrans | UsrNm
--------------------------
| Evt1 | edit | Usr4
| Evt2 | reverse | Usr1
| Evt3 | validate | Usr3
| Evt4 | add | Usr3
| Evt5 | add | Usr2
Much thanks for any assistance.
Something like this shuold work where a derived table is used to eliminate all transactions except the latest per evId.
SELECT
eventTable.EvtName AS EvtD,
transTable.TranAct AS LastTrans,
userTable.UserName AS UsrNm,
FROM
transTable
INNER JOIN (
SELECT evId, MAX(UID) uid FROM transTable GROUP BY evId
) last ON last.evId = transTable.evId AND last.uid = transTable.uid
INNER JOIN eventTable ON eventTable.evId = transTable.evId
INNER JOIN userTable ON userTable.usId = transTable.usId