I have a table as follows:
------+-------------+------------+----------------+------------------------------------------------+
| id | customer_id | date | action_type_id | details |
+------+-------------+------------+----------------+------------------------------------------------+
| 4225 | 324 | 2015-09-07 | 1 | Sent mail Malcolm Murrey |
| 6320 | 324 | 2017-05-08 | 3 | quotes for price. |
| 156 | 326 | 2013-07-25 | 3 | Site visit to price job |
| 943 | 326 | 2013-10-23 | 1 | Arranged visit for snags on panel |
| 1135 | 326 | 2013-11-28 | 1 | Arranged visit for site mod |
| 1930 | 326 | 2014-04-15 | 2 | Quoted for new HMI |
| 2644 | 326 | 2014-10-20 | 2 | Sent email about pending quote for HMI |
| 2821 | 326 | 2014-11-25 | 1 | Screen problem |
| 2184 | 328 | 2014-07-21 | 1 | Sent email detailing services |
+------+-------------+------------+----------------+------------------------------------------------+
I'm trying to find the customer_id of customers that don't have an action_type_id of 2. In this case 324 and 328 but just can't seem to figure it out.
I was thinking I could do something like group by customer_id not having action_type_id = 2.... any help much appreciated.
I would use aggregation:
select customerid
from t
group by customerid
having sum(action_type_id = 2) = 0;
I find the use of group by and having for this type of query to be very flexible on the conditions you might have (say you want 2 and 3, or not 2 but either 3 or 4).
You can do this by a left join to itself on records with an id of 2, then filtering on those without a match.
Something along the lines of
SELECT DISTINCT customer_id
FROM customer a
LEFT JOIN customer b
ON a.customer_id = b.customer_id
AND b.action_type_id = 2
WHERE b.customer_id IS NULL
Why not just use not exist:
select *
from table t
where not exists (select 1 from table
where customer_id = t.customer_id and
action_type_id = 2);
Why not this,
select distinct customer_id from customer where action_type_id <> 2
This should work:
SELECT customer_id FROM customers WHERE action_type_id <> 2
Related
I have a script which is working but not as desired. My aim is to select the most recently inputted record on the plans database for each seller in the account_manager_sellers list.
The current issue with the script below is: It is returning the oldest record rather than the newest, for example: it is selecting a record in 2016 rather than one which has a timestamp in 2018. (eventually I need to change the WHERE clause to get all lastsale records before 2017-01-01.
Simple Database Samples.
plans AKA (sales list)
+----+------------------+-----------+
| id | plan_written | seller_id |
+----+------------------+-----------+
| 1 | 20/09/2016 09:12 | 123 |
| 2 | 22/12/2016 09:45 | 444 |
| 3 | 19/10/2016 09:07 | 555 |
| 4 | 02/10/2015 14:26 | 123 |
| 5 | 15/08/2016 11:06 | 444 |
| 6 | 16/08/2016 11:03 | 123 |
| 7 | 03/10/2016 10:15 | 555 |
| 8 | 28/09/2016 10:12 | 123 |
| 9 | 27/09/2016 15:12 | 444 |
+----+------------------+-----------+
account_manager_sellers (seller list)
+-----+----------+
| id | name |
+-----+----------+
| 123 | person 1 |
| 444 | person 2 |
| 555 | person 3 |
+-----+----------+
Current Code Used
SELECT p.plan_written, p.seller_id
FROM plans AS p NATURAL JOIN (
SELECT id, MAX(plan_written) AS lastsale
FROM plans
GROUP BY seller_id
) AS t
JOIN account_manager_sellers AS a ON a.id = p.seller_id
WHERE lastsale < "2018-05-08 00:00:00"
Summary
Using the code and example tables above, this code would return these 3 results, whilst we do expect 3 results, the MAX(plan_written) does not seem to have followed, my guess is that it is something to do with the GROUP clause, I am not sure if we can utilise an ORDER BY and LIMIT clause?
+--------------+------------------+
| seller_id | plan_written |
+--------------+------------------+
| 123 | 16/08/2016 11:03 |
| 444 | 15/08/2016 11:06 |
| 555 | 03/10/2016 10:15 |
+--------------+------------------+
The join condition in your query is off, and you should be restricting to the max date for each seller. Also, you don't need to join to the account_manager_sellers table to get your expected output:
SELECT p1.*
FROM plans p1
INNER JOIN
(
SELECT
seller_id, MAX(plan_written) AS max_plan_written
FROM plans
WHERE plan_written < '2018-05-08 00:00:00'
GROUP BY seller_id
) p2
ON p1.seller_id = p2.seller_id AND
p1.plan_written = p2.max_plan_written;
The following are the three tables I have where session.id = signup.session_id AND session.loc_id = location.id. The max override is as the name suggest override the default max capacity for the location hence IFNULL(session.max_override, location.max_cap).
mysql> SELECT * FROM session;
+----+---------------------+---------------+--------+
| id | date_time | max_override | loc_id |
+----+---------------------+---------------+--------+
| 1 | 2014-02-04 10:30:00 | 35 | 2 |
| 2 | 2014-02-04 17:00:00 | | 2 |
| 3 | 2014-02-06 11:30:00 | 50 | 2 |
| 4 | 2014-02-09 13:30:00 | | 1 |
+----+---------------------+---------------+--------+
mysql> SELECT * FROM location;
+-----------------+---------+
| id | location | max_cap |
+-----------------+---------+
| 1 | up | 20 |
| 2 | down | 103 |
| 3 | right | 50 |
| 4 | left | 50 |
+-----------------+---------+
mysql> SELECT * FROM signups;
+-----------------+------------+
| id | name | session_id |
+-----------------+------------+
| 1 | test | 3 |
| 2 | admin | 1 |
| 3 | meme | 2 |
| 4 | anna | 4 |
+-----------------+------------+
The report I am trying to create looks simple but I am not sure how to approach the problem. The following is how I would like the report/output to look like..
mysql> query ouput;
+------------+----------+-----------+----------+----------+-----------+----------+
| date | am_time | am_ses_id | am_spots | pm_time | pm_ses_id | pm_spots |
+------------+----------+-----------+----------+----------+-----------+----------+
| 2014-02-04 | 10:30 AM | 1 | 34 | 05:00 PM | 2 | 102 |
| 2014-02-06 | 11:30 AM | 3 | 49 | | | |
| 2014-02-09 | | | | 01:30 PM | 4 | 49 |
+------------+----------+-----------+----------+----------+-----------+----------+
I can group the date and time correctly and also managed to get the session_id to match since it is all within one table but to calculate the am/pm spots which is nothing but counting the records in signups table for a particular session and deducting the value from either the max_cap or max_override depending on the situation.
THIS is what I tried
Using the following query
SELECT
DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
DATE_FORMAT(a.date_time,'%r') AS ses_time,
a.id,
COUNT(b.id) as signed_up,
IFNULL(a.max_override,c.max_cap) AS cap
FROM
test.session a
LEFT JOIN
test.signups b
ON (b.session_id = a.id)
LEFT JOIN
test.location c
ON (c.id = a.loc_id)
GROUP BY b.session_id
I get the following output
+------------+----------+--------+-----------+------+
| date | ses_time | ses_id | signed_up | cap |
+------------+----------+--------+-----------+------+
| 2014-02-04 | 10:30 AM | 1 | 1 | 35 |
| 2014-02-04 | 05:00 PM | 2 | 1 | 103 |
| 2014-02-06 | 10:30 AM | 3 | 1 | 50 |
| 2014-02-09 | 10:30 AM | 4 | 1 | 50 |
+------------+----------+--------+-----------+------+
But I cannot seem to find a way to group it only by the date so the output would appear like desired! I don't know if I should union two queries either.
Here is a very convoluted way of doing it...
sqlfiddle: http://sqlfiddle.com/#!2/d85ca/11
select c.ses_date `date`, a.ses_time am_time, a.id am_ses_id, a.cap-a.signed_up am_spots,
b.ses_time pm_time, b.id pm_ses_id, b.cap-b.signed_up pm_spots
from (
select distinct DATE_FORMAT(a.date_time,'%m/%d/%Y') ses_date
from session a) c
left join (
SELECT
DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
DATE_FORMAT(a.date_time,'%r') AS ses_time,
a.id,
COUNT(b.id) as signed_up,
IFNULL(a.max_override,c.max_cap) AS cap
FROM
session a
LEFT JOIN
signups b
ON (b.session_id = a.id)
LEFT JOIN
location c
ON (c.id = a.loc_id)
where date_format(a.date_time, '%p') = 'AM'
GROUP BY b.session_id) a on c.ses_date = a.ses_date
left join (
SELECT
DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
DATE_FORMAT(a.date_time,'%r') AS ses_time,
a.id,
COUNT(b.id) as signed_up,
IFNULL(a.max_override,c.max_cap) AS cap
FROM
session a
LEFT JOIN
signups b
ON (b.session_id = a.id)
LEFT JOIN
location c
ON (c.id = a.loc_id)
where date_format(a.date_time, '%p') = 'PM'
GROUP BY b.session_id) b on c.ses_date = b.ses_date;
You need to use the JOIN operator to let the SQL DB know the relationship between the tables.
In this case also, it may be easier to do a subquery to get the count (to avoid GROUP BY). I've not separated out AM and PM by day but you could do that.
SELECT session.date_time,
IFNULL(session.max_override,location.max_cap)-(
SELECT COUNT(signups.id)
FROM signups
WHERE signups.session_id = session.id) as avail_spots
FROM session LEFT JOIN location ON session.loc_id = location.id;
Note the LEFT JOIN will include 2014-02-04 17:00:00 with a NULL avail_spots since neither max_override nor max_cap have a value, whereas INNER JOIN would not report that session at all.
fiddle
EDIT: once you have the information by day you can use it on output. Trying to pivot out the times but grouping on the date adds a lot of complexity to the query that could be solved a lot more simply by whatever program you are using for your UI.
I have 3 tables with information.
Table1: Orders
+---------+----------------+------------+---------------+
| OrderID | OrderDate | Community | Status |
+-------------------------------------------------------+
1 | 1 march 2013 | S1 | Approved
2 | 5 march 2013 | S2 | Aporoved
3 | 7 march 2013 | Z1 | Approved
+-------------------------------------------------------+
Table2: OrderArtickles
+------------------------------------------------------------------+
|Ordertitem | OrderID | ArtikelID | UnitPrice | Delivered |
+------------------------------------------------------------------+
| 1 | 1 | 20 | 5 | yes
| 2 | 1 | 20 | 5 | yes
| 3 | 2 | 21 | 10 | yes
| 4 | 3 | 30 | 50 | yes
+-------------------------------------------------------------------+
Table3: users
+-----------------------------------------------------+
| Userid | Username | Community | Department |
+-----------------------------------------------------+
| 1 | User1 | S1 | S
| 2 | User2 | S2 | S
| 3 | User3 | Z1 | Z
+-----------------------------------------------------+
I need a MySQL query that give the following output:
+--------------------------------------+
| Department | TotalPriceOfArtikels
+--------------------------------------+
| S | 20
| Z | 50
+--------------------------------------+
I tried with JOIN, SUM, GROUP BY but without result. The problem that I have is that the one order gives multiple articles. Who can help me?
try this
select Department , sum(UnitPrice) as TotalPriceOfArtikels
from users u
inner join Orders o
on o.Community = u.Community
inner join OrderArtickles oa
on oa.OrderId = o.OrderId
group by Department
DEMO HERE
OUTPUT:
Department TotalPriceOfArtikels
S 20
Z 50
Something like this:
select us.Department,
sum ( art.UnitPrice ) as TotalPriceOfArtikels
from user us
left join orders ors
on ( us.Community = ors.Community)
left join OrderArtickles art
on ( ors.OrderID = art.OrderID)
group by us.Department
------------------EDITED------------------------
I copy the same values and structures of your tables in my mysql, and the result is fine, it give me:
Department TotalPriceOfArtikels
S 20
Z 50
Maybe you want to check a condition, like if delivered = yes or status = aprobed??....with this query the result it's the same that you have posted ;)
Saludos ;)
I have the following code and I would like to select only the most recent record (hence why I have written max(a.fiscal_year) except the query returns every fiscal year. How can I adjust the following query to return only the most recent (maximum) fiscal year.
SELECT count(*), b.auditor_name, c.pubco_name, max(a.fiscal_year), a.month
FROM a_fees_view a, a_auditor b, a_pubco c
WHERE a.auditor_id = b.auditor_id AND a.pubco_id = c.pubco_id
GROUP BY a.auditor_id, a.pubco_id, a.fiscal_year
ORDER BY b.auditor_name, c.pubco_name, a.fiscal_year
Furthermore, I would like to select ALL pubcos from the a_pubco table and not just the one's that are also present in the a_fees_view table. How can I adjust the query above to include all the pubco's that are in both the a_fees_view table and the a_pubco table.
The first part of this problem is a Top-N (or Groupwise-max) query. The usual syntax is as follows:
SELECT x.*
FROM my_table x
JOIN (SELECT grouping_id, MAX(other_field) max_other_field FROM my_table GROUP BY grouping_id) y
ON y.grouping_id = x.grouping_id
AND y.max_other_field = x.other_field;
Consider the following example (inspired by a question asked elsewhere):
I have a table of results from showjumping events. I want to find out in which event each horse did best (and what result they achieved).
SELECT * FROM events;
+----------+----------+-------+
| Event_id | Horse_id | Place |
+----------+----------+-------+
| 601 | 101 | 1 |
| 601 | 102 | 2 |
| 601 | 201 | 3 |
| 601 | 301 | 4 |
| 602 | 201 | 2 |
| 603 | 201 | 3 |
| 701 | 101 | 1 |
| 801 | 301 | 2 |
| 901 | 102 | 7 |
+----------+----------+-------+
From inspection, I can see that horse 101's best result was '1st' which she achieved in two events, so I want both of those rows to be returned.
Horse 102's best result was '2nd', as was horse 201's and horse 301's. But how to construct a query that tells us that? Here's how:
SELECT x.*
FROM events x
JOIN (SELECT horse_id,MIN(place) min_place FROM events GROUP BY horse_id) y
ON y.horse_id = x.horse_id AND y.min_place = x.place;
+----------+----------+-------+
| Event_id | Horse_id | Place |
+----------+----------+-------+
| 601 | 101 | 1 |
| 601 | 102 | 2 |
| 602 | 201 | 2 |
| 701 | 101 | 1 |
| 801 | 301 | 2 |
+----------+----------+-------+
First off, sorry if this is a near enough duplicate. I've found this question, which nearly does what I want, but I couldn't wrap my head around how to alter it to my needs.
I've got these 3 tables:
cs_Accounts:
+----+-----------------------------+-------------+
| id | email | username |
+----+-----------------------------+-------------+
| 63 | jamasawaffles#googlil.com | jamwaffles2 |
| 64 | jamwghghhfles#goomail.com | jamwaffles3 |
| 65 | dhenddfggdfgetal-pipdfg.com | dhendu9411 |
| 60 | jwapldfgddfgfffles.co.uk | jamwaffles |
+----+-----------------------------+-------------+
cs_Groups:
+----+-----------+------------+-------------+
| id | low_limit | high_limit | name |
+----+-----------+------------+-------------+
| 1 | 0 | 0 | admin |
| 2 | 1 | 50 | developer |
| 3 | 76 | 100 | reviewer |
| 4 | 51 | 75 | beta tester |
| 5 | 1 | 50 | contributor |
+----+-----------+------------+-------------+
cs_Permissions:
+----+---------+----------+
| id | user_id | group_id |
+----+---------+----------+
| 4 | 60 | 4 |
| 3 | 60 | 1 |
| 5 | 60 | 2 |
| 6 | 62 | 1 |
| 7 | 62 | 3 |
+----+---------+----------+
I've been wrestling with a 3 way join for hours now, and I can't get the results I want. I'm looking for this behaviour: a row will be returned for every user from cs_Accounts where there is a row in cs_Permissions that contains their ID and the ID of a group from cs_Groups, as well as the group with the group_id has a high_lmiit and low_limit in a range I can specify.
Using the data in the tables above, we might end up with something like this:
email username cs_Groups.name
----------------------------------------------------------
jwapldfgddfgfffles.co.uk jamwaffles admin
jwapldfgddfgfffles.co.uk jamwaffles developer
jwapldfgddfgfffles.co.uk jamwaffles beta tester
dhenddfggdfgetal-pipdfg.com dhendu9411 admin
dhenddfggdfgetal-pipdfg.com dhendu9411 reviewer
There is an extra condition, however. This condition is where rows are only selected if the group the user belongs to has a high_limit and low_limit with values I can specify using a WHERE clause. As you can see, the table above only contains users with rows in the permissions table.
This feels a lot like homework but with a name like James I'm always willing to help.
select a.email,a.username,g.name
from cs_Accounts a
inner join cs_Permissions p on p.user_id = a.id
inner join cs_Groups g on g.id = p.Group_id
where g.low_limit > 70
and g.high_limt < 120
This is the query
SELECT ac.email, ac.username, gr.name
FROM cs_Accounts AS ac
LEFT JOIN cs_Permissions AS per ON per.user_id = ac.id
INNER JOIN cs_Groups AS gr ON per.user_id = gr.id
You can add a WHERE clause to this query if you want