I have this table named "events" in my mysql database:
+-----+-----------+------------------------------+------------+
| ID | CATEGORY | NAME | TYPE |
+-----+-----------+------------------------------+------------+
| 1 | 1 | Concert | music |
| 2 | 2 | Basketball match | indoors |
| 3 | 1 | Theather play | outdoors |
| 4 | 1 | Concert | outdoors |
+-----+-----------+------------------------------+------------+
I need a query to count the events with category 1 and which type is music and also outdoors
Meaning that from the table above the count should be only 1: there are three events with category 1
but only "Concert" has type outdoor and music (ID 1 and ID 4).
What would be that query? Can that be done?
Try this:
SELECT count(DISTINCT e1.name)
FROM `events` AS e1
JOIN `events` AS e2 ON e1.name = e2.name
WHERE e1.category = 1
AND e2.category = 1
AND e1.type = 'music'
AND e2.type = 'outdoor'
Or a harder to understand way, but way faster than the previous one:
SELECT count(*) FROM (
SELECT `name`
FROM `events`
WHERE `category` = 1
GROUP BY `name`
HAVING SUM( `type` = 'music') * SUM( `type` = 'outdoor' ) >= 1
) AS notNeeded
For 2 criteria I would use Alin's answer. An approach you can use for greater numbers is below.
SELECT COUNT(*)
FROM (SELECT `name`
FROM `events`
WHERE `category` = 1
AND `type` IN ( 'outdoors', 'music' )
GROUP BY `name`
HAVING COUNT(DISTINCT `type`) = 2) t
Try this query
Select count(*), group_concat(TYPE SEPARATOR ',') as types
from events where category = 1
HAVING LOCATE('music', types) and LOCATE('outdoors', types)
try:
SELECT * FROM `events` AS e1
LEFT JOIN `events` AS e2 USING (`name`)
WHERE e1.`category` = 1 AND e2.`category` = 1 AND e1.`type` = 'music' AND e2.`type` = 'outdoors'
SELECT COUNT(*)
FROM table
WHERE category=1
AND type='music' AND type IN (SELECT type
FROM table
WHERE type = 'outdoor')
one line keeps resetting my connection. wth? i'll try posting as a comment
Select count(distinct ID) as 'eventcount' from events where Category = '1' and Type in('music','outdoor')
Related
For every same date (this is just one section of the table), I want to return the account numbers that made a purchase of A but DID NOT purchase B, and another query for vice-versa. So running the first query for A but no B should return 2 and 5. Running the vice-versa query for B but no A should give me 4. Thanks for the help. I'm assuming I would have to do a join of some sorts on the table but I'm stuck.
+----+----------------+---------------+----------+--+--+
| ID | Account Number | Purchase Type | Date | | |
+----+----------------+---------------+----------+--+--+
| 1 | 1 | A | 20140301 | | |
| 1 | 1 | A | 20140301 | | |
| 1 | 1 | B | 20140301 | | |
| 2 | 2 | A | 20140301 | | |
| 3 | 3 | A | 20140301 | | |
| 3 | 3 | B | 20140301 | | |
| 4 | 4 | B | 20140301 | | |
| 5 | 5 | A | 20140301 | | |
| 5 | 5 | A | 20140301 | | |
+----+----------------+---------------+----------+--+--+
Not sure if it is necessarily the best approach, but an inner select will work:
select distinct account_number
from purchases p
where purchase_type = "A" and account_number not in
(
select account_number
from purchases
where purchase_date = p.purchase_date and purchase_type = "B"
)
You first collect all ids that have purchase type "B" and then all ids with purchase type "A" that are not in the first collection.
(Assuming your table is purchases, ID is id int, Purchase Date is purchase_date char(1) and Date is purchase_date char(8), but you should be able to adapt the query to your actual columns.
Corresponding fiddle: http://sqlfiddle.com/#!9/edf73f/7/0)
One approach would be to use a full outer join where one or the other side is null; but mySQL doesn't support them. So to simulate: use a left join and then a union (or union all if you want to keep the fact that 1,1,A exists twice.) and we simply switch the criteria between the joins for the second SQL to union to handle both ways.
DEMO using SQL fiddle in comment: http://sqlfiddle.com/#!9/52c893/20/0
SELECT A.*
FROM purch A
LEFT JOIN purch B
on A.`Account Number` = B.`Account Number`
AND B.`Purchase Type` = 'B'
WHERE b.`Account Number` is null
AND A.`Purchase Type` = 'A'
UNION ALL
SELECT A.*
FROM purch A
LEFT JOIN purch B
on A.`Account Number` = B.`Account Number`
AND B.`Purchase Type` = 'A'
WHERE b.`Account Number` is null
AND A.`Purchase Type` = 'B'
You can use Exists on the same table:
select distinct AccountNumber , Date
from table1 outer_table
where PurchaseType = 'A' and not exists
(
select ID
from table1 inner_table
where
PurchaseType = 'B'
and inner_table.Date = outer_table.Date
and inner_table.AccountNumber = outer_table.AccountNumber
)
Fiddle: http://sqlfiddle.com/#!9/b84ecd/9
select id,sum(if(purchase_type='A',1,0)) as sumA,sum(if(purchase_type='B',1,0)) as sumB
from purchases
group by id
having sumA>0 and sumB=0
Fiddle: http://sqlfiddle.com/#!9/edf73f/16
and to get the two request in one:
select id,sum(if(purchase_type='A',1,0)) as sumA,sum(if(purchase_type='B',1,0)) as sumB
from purchases
group by id
having (sumA>0 and sumB=0) OR(sumA=0 and sumB>0 )
Fiddle: http://sqlfiddle.com/#!9/edf73f/18
You get a bit messed up here because MySQL's set arithmetic operations are incomplete. It has UNION and INTERSECT but not EXCEPT. If it had EXCEPT you could do
SELECT DISTINCT `Account Number` FROM purch WHERE `Purchase Type` = 'A'
EXCEPT /* MySQL fail! */
SELECT DISTINCT `Account Number` FROM purch WHERE `Purchase Type` = 'B'
and your problem would be solved.
So you can use the LEFT JOIN ... IS NULL query pattern. It's more verbose but works fine. (http://sqlfiddle.com/#!9/52c893/18/0)
SELECT suba.`Account Number`
FROM (
SELECT DISTINCT `Account Number`
FROM purch
WHERE `Purchase Type` = 'A'
) suba
LEFT JOIN (
SELECT DISTINCT `Account Number`
FROM purch
WHERE `Purchase Type` = 'B'
) subb ON suba.`Account Number` = subb.`Account Number`
WHERE subb.`Account Number` IS NULL
SELECT GROUP_CONCAT( DISTINCT A.account SEPARATOR ', ') AS "accounts"
FROM test A, test B
WHERE A.type='A'
AND A.id=B.id
AND A.date=B.date
AND A.date='2014-03-01'
I have this query
SELECT
`from_id` as user_id,
MAX(`createdon`) as updated_at,
SUM(`unread`) as new,
u.username,
p.sessionid,
s.access
FROM (
SELECT `from_id`, `createdon`, `unread`
FROM `modx_messenger_messages`
WHERE `to_id` = {$id}
UNION
SELECT `to_id`, `createdon`, 0
FROM `modx_messenger_messages`
WHERE `from_id` = {$id}
ORDER BY `createdon` DESC
) as m
LEFT JOIN `modx_users` as u ON (u.id = m.from_id)
LEFT JOIN `modx_user_attributes` as p ON (p.internalKey = m.from_id)
LEFT JOIN `modx_session` as s ON (s.id = p.internalKey)
GROUP BY `from_id`
ORDER BY `new` DESC, `createdon` DESC;
table
id | message | createdon | from_id | to_id | unread
1 | test | NULL | 5 | 6 | 0
2 | test2 | NULL | 6 | 5 | 1
3 | test3 | NULL | 6 | 5 | 1
result new = 28. Why?
If remove joins new = 2, correctly.
Though it depends on the actual database, pure SQL says that a statement using GROUP BY requires all non-aggregated columns to be in the GROUP BY. Without including all columns, weird stuff can happen, which might explain why you get different results. If you know that the other columns are going to be the same within the user_id, you could do MAX(u.username) or something similar (again, depending on your database server). So I'd try and clean up the SQL statement first.
Trades
id |Trade_name |
1 | trade1 |
2 | trade2 |
3 | trade3 |
4 | trade4 |
Users
Name | Primary_id(FK to trade.id) | secondary_id (FK to trade.id) |
John | 1 | 2 |
Alex | 3 | 4 |
This is my current SQL which joins trades.t1 to primary & secondary.id:
select
`users`.`name` ,
`t1`.`trade_name` AS `Primary_trade`,
`t2`.`trade_name` AS `Secondary_trade`,
FROM `users`
right JOIN `trades` `t1` On (`t1`.`trade_id` = `users`.`primary_trade_id`)
right JOIN `trades` `t2` on (`t2`.`trade_id` = `users`.`secondary_trade_id`)
My question is, how do I identify which trades are not used for users both as primary or secondary. I want to see record where a trade does not exist in both primary or secondary column so I can perform housekeeping.
Thanking you all in advance for your help.
If you need only the trades rows
SELECT t.*
FROM trades t
WHERE NOT EXISTS ( SELECT 'u'
FROM Users u
WHERE u.Primary_id = t.id
OR u.Secondary_id = t.id
)
I think this should work for you:
SELECT * FROM trades WHERE id NOT IN (SELECT Primary_id FROM Users) AND id NOT IN (SELECT Secondary_id FROM Users)
It selects the rows which are not in either primary_id nor secondary_id
I have a table of the following structure:
ID | COMPANY_ID | VERSION | TEXT
---------------------------------
1 | 1 | 1 | hello
2 | 1 | 2 | world
3 | 2 | 1 | foo
is there a way to get the most recent version of records only, i.e. I would want to have as a result set the IDs 2 and 3?
I'm sure there are better ways, but I tend to use this kind of query:
SELECT *
FROM
(SELECT * FROM test ORDER BY VERSION DESC) AS my_table
GROUP BY COMPANY_ID
Produces this result set:
ID | COMPANY_ID | VERSION | TEXT
---------------------------------
2 | 1 | 2 | world
3 | 2 | 1 | foo
Try this:
SELECT *
FROM (
SELECT company_id, MAX(version) maxVersion
FROM table
GROUP BY company_id ) as val
JOIN table t ON (val.company_id = t.company_id AND t.version = val.maxversion)
If your IDs are ordered (newer version iff higher id):
SELECT t.*, a.maxversion
FROM (
SELECT MAX(id) maxid, MAX(version) maxversion
FROM table
GROUP BY company_id
) a
INNER JOIN table t
ON a.maxid = t.id
However, if your IDs are not properly ordered, you need to use the following query:
SELECT t.*
FROM (
SELECT company_id, MAX(version) maxversion
FROM table
GROUP BY company_id
) v
INNER JOIN table t
ON v.company_id = t.company_id
AND v.maxversion = t.version
(assuming there's an UNIQUE constraint/index on (company_id, version))
Say I have the following table:
=================================================
| color_id | parent_id | language_id | name |
=================================================
| 1 | 50 | 1 | Black |
-------------------------------------------------
Then say I need the row WHERE parent_id = 50 AND language_id = 2. Obviously, I would get nothing back based on my example table. However, I still need a result -- probably something like this:
=================================================
| color_id | parent_id | language_id | name |
=================================================
| NULL | 50 | 2 | NULL |
-------------------------------------------------
Is there a way to do this in SQL?
You could do a union query of both the potentially valid record and your default, then select the first one:
SELECT * FROM
(SELECT color_id, parent_id, language_id, name, 1 as order_rank
FROM some_table
WHERE parent_id = %parent_id% AND language_id = %language_id%
UNION
SELECT NULL, %parent_id%, %language_id%, NULL, 2 as order_rank
)
ORDER BY order_rank
LIMIT 1
(Edited with static value for ordering as suggested by OMG Ponies)
try working with LEFT JOIN statement. i'm probably not doing this 100% but a bit of trial and error on your part should make this work.
SELECT table1.field1, table1.field2, table2.field3, table2.field4
FROM my_table table1
LEFT JOIN my_table table2 ON table1.field1=table2.field1 OR table1.field2=table2.field2
a left join on a forced fixed value first table SHOULD work.
select
YourTable.color_id,
ForcedSQL1Record.parent_id,
ForcedSQL1Record.language_id,
YourTable.name
from
( select 50 as Parent_ID,
2 as Language_ID
from YourTable
limit 1 ) ForcedSQL1Record
left join
YourTable
on ForcedSQL1Record.Parent_ID = YourTable.Parent_ID
AND ForcedSQL1Record Language_ID = YourTable.Language_ID