I'm trying to select all my areas and join the deals for those areas... this query is returning 0 results when I have verified that I have data to match what I'm expecting to get... does anyone see anything obviously wrong?
SELECT
deal.*,
area.id AS area_id
FROM area
INNER JOIN account_areas ON (
account_areas.account_id = 1 AND
account_areas.area_id = area.id
)
JOIN deal ON (
deal.area_id = area.id AND
deal.site_id = 1 AND
DAYOFYEAR(deal.created) = DAYOFYEAR(NOW()) AND
deal.end >= NOW()
)
ORDER BY area.name ASC
The idea is that I want to pull all deals for a certain area, but if there are no deals, still have the area in the result query.
account
---------------------------------
| id | email |
---------------------------------
| 1 | test_test.com |
---------------------------------
account_areas
------------------------
| account_id | area_id |
------------------------
| 1 | 81 |
| 1 | 42 |
------------------------
deal
--------------------------------------------------------
| id | area_id | Title |
--------------------------------------------------------
| 1 | 81 | Test Title |
--------------------------------------------------------
Expected results WITH a deal:
id | area_id | title
Expected results WITHOUT a deal
area_id
Use a ...LEFT JOIN DEAL... which will return nulls for all DEAL columns if there are no deals.
Related
I got working code from three queries but I would like to combine them into one or two. Basically I am checking if a provided phone number exists in table contacts or leads as well as if it exists as a secondary number in customfieldsvalues (not all leads have a customfield value though). I am using a CRM system based on CodeIgniter.
What I want to do (non-correct/hypothetical query):
SELECT * FROM contacts OR leads WHERE phonenumber = replace(X, '-', '')
OR leads.id = customvaluefields.relid AND cfields.fieldid = 41 AND cfields.value = X
Tables
table : contacts
+-------+----------------+----------------+
| id | firstname | phonenumber |
+-------+----------------+----------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+----------------+----------------+
table : leads
+-------+-----------+---------------------+
| id | name | phonenumber |
+-------+-----------+---------------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+-----------+---------------------+
table : customvaluefields
+-------+-----------+-------------+-----------+
| id | relid | fieldid | value |
+-------+-----------+-------------+-----------+
| 1 | 1 | 41 | 222333444 |
| 2 | 1 | 20 | Management|
| 3 | 2 | 41 | 333444555 |
+-------+-----------+-------------+-----------+
If I understand what you are trying to, maybe UNION ALL would work. This is something to get you started:
SELECT C.ID, C.FirstName, C.Phonenumber
FROM Contacts C
JOIN CustomValueField CVF
ON c.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
UNION ALL
SELECT L.ID, L.FirstName, L.Phonenumber
FROM Leads L
JOIN CustomValueField CVF
ON L.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
I'm joining the contacts and leads tables to CustomeValueField in each query and then UNION them together along with the WHERE clause in each. I'm sure it's not 100% correct for what you need, but should get you headed to a solution. Here is more information: https://dev.mysql.com/doc/refman/8.0/en/union.html
I have database table like
transactions
-----------
id
code
date
amount
formalities
-----------
id
transaction_id
this is query to get max value of transactions
SELECT MAX(transaction_id) FROM `transactions` n LEFT JOIN `formalities` r ON r.transaction_id = n.id
But what I want to achieve here is to get the max value of id group by transactions code, but the value must check if the transactions have relation to formalities or not.
If yes, get max value where they relate.
If not just get the usual max value.
Is there a query to achieve something like this?
example:
transactions
--------------------
id | code | amount |
1 | ABC | 10000 |
2 | ABC | 20000 |
3 | KOO | 10000 |
4 | ABC | 20000 |
5 | KOO | 30000 |
6 | KOO | 10000 |
formalities
-----------
id | transaction_id |
1 | 3 |
2 | 5 |
The result I want is getting the following output from the transactions table
id
--
4
5 ( priority the one that have relation and get the max value)
Use a LEFT JOIN and get both - MAX(transactions.id) and MAX(formalities.transaction_id):
select t.code, max(f.transaction_id), max(t.id)
from transactions t
left join formalities f on f.transaction_id = t.id
group by t.code
The result would be
| code | max(f.transaction_id) | max(t.id) |
| ---- | --------------------- | --------- |
| ABC | NULL | 4 |
| KOO | 5 | 6 |
View on DB Fiddle
To "prioritize" transaction_id column from formalities table you can use COALESCE(), which will return the first non NULL value:
select t.code, coalesce(max(f.transaction_id), max(t.id)) as max_transaction_id
from transactions t
left join formalities f on f.transaction_id = t.id
group by t.code
Result:
| code | max_transaction_id |
| ---- | ------------------ |
| ABC | 4 |
| KOO | 5 |
View on DB Fiddle
I am not sure if I am getting the question right, but why don't you simply use -
SELECT MAX(transaction_id) FROM `transactions` n INNER JOIN `formalities` r ON r.transaction_id = n.id group by n.code
+------+---------+--------+---------+---------+---------+
| id | user_id | obj_id | created | applied | content |
+------+---------+--------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 1 | ... |
| 2 | 1 | 2 | 1 | 1 | ... |
| 3 | 1 | 1 | 1 | 2 | ... |
| 4 | 1 | 2 | 2 | 2 | ... |
| 5 | 2 | 1 | 1 | 1 | ... |
| 6 | 2 | 2 | 1 | 1 | ... |
+------+---------+--------+---------+---------+---------+
I have a table similar to the one above. id, user_id and obj_id are foreign keys; created and applied are timestamps stored as integers. I need to get the entire row, grouped by user_id and obj_id, with the maximum value of applied. If two rows have the same applied value, I need to favour the maximum value of created. So for the above data, my desired output is:
+------+---------+--------+---------+---------+---------+
| id | user_id | obj_id | created | applied | content |
+------+---------+--------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 1 | ... |
| 4 | 1 | 2 | 2 | 2 | ... |
| 5 | 2 | 1 | 1 | 1 | ... |
| 6 | 2 | 2 | 1 | 1 | ... |
+------+---------+--------+---------+---------+---------+
My current solution is to get everything ordered by applied then created:
select * from data order by applied desc created desc;
and sort things out in the code, but this table gets pretty big and I'd like an SQL solution that just gets the data I need.
select *
from my_table
where id in (
/* inner subquery b */
select max(id)
from my_table where
(user_id, obj_id, applied, created) in (
/* inner subquery A */
select user_id, obj_id, max(applied), max(created)
from my_table
group by user_id, obj_id
)
);
Then inner subquery A return the (distinct) rows having user_id, obj_id, max(applied), max(created). Using these with in clause the subquery B retrive a list of single ID each realated the a row with a proper value of user_id, obj_id, max(applied), max(created). so you have a collection of valid id for getting your result.
The main select use these ID for select the result you need.
Thanks to Mark Heintz in the comments, this answer got me to where I need to be.
SELECT
data.id,
data.user_id,
data.obj_id,
data.created,
data.applied,
data.content
FROM data
LEFT JOIN data next_max_applied ON
next_max_applied.user_id = data.user_id AND
next_max_applied.obj_id = data.obj_id AND (
next_max_applied.applied > data.applied OR (
next_max_applied.applied = data.applied AND
next_max_applied.created > data.created
)
)
WHERE next_max_applied.applied IS NULL
GROUP BY user_id, obj_id;
Go read the answer for details on how it works; the left join tries to find a more recently applied row for the same user and object. If there isn't one, it will find a row applied at the same time, but created more recently.
The above means that any row without a more recent row to replace it will have a next_max_applied.applied value of null. These rows are filtered for by the IS NULL clause.
Finally, the group by clause handles any rows that have identical user, object, applied and created columns.
I'm working with MySQL
I have a Actions_table which has an action an number of users.
I also have a Timing_table which I map the timing of each action to do.
I can match up the action in the Actions table to the Timing table but I want it to use a default time if there is no exact match eg tables
Actions_Table
------------------------------
| Action | No Ids |
------------------------------
|Delete ID | 5 |
|Install App1 | 1 |
|Create ID | 1 |
|Rename ID | 2 |
------------------------------
Timing_Table
-------------------
|Action |Time |
-------------------
|Delete ID | 100 |
|Install App1| 200 |
|Create ID | 50 |
|Default | 60 |
--------------------
As there is nothing listed for "Rename ID" in the Timings_Table I want it to use the time value for 'Default' instead so I will have something link this.
-------------------------------------
| Action | No Ids | Total Time|
-------------------------------------
|Delete ID | 5 | 500 |
|Install App1 | 1 | 200 |
|Create ID | 1 | 50 |
|Rename ID | 2 | 120 | <== value was calculated from Default
-------------------------------------
The basic code
Select a.Action, a.`No Ids`, (a.`No Ids` * b.time) as `TotalTime
From Action_Table a, Timing_Table b
Where a.Action = b.Action
However that won't match any unmatched to Default.
What you want is a left join and a cross join:
Select a.Action, a.`No Ids`,
coalesce(b.time, def.time) as ImputedBTime,
(a.`No Ids` * coalesce(b.time, def.time)) as `TotalTime
From Action_Table a left join
Timing_Table b
on a.Action = b.Action cross join
(select t.* from Timing_Table t where t.action = 'default') def
Simple rule: Never use commas in the from clause. Always use explicit JOIN syntax. You should learn the different types of joins.
I'm having a problem with joining 2 queries but in the second query I only want to bring in the count.
This first query works well
SELECT DISTINCT forum_sub.sub_id, forum_id, title, text, url, forum_sub.userid, members.first_name, views
FROM forum_sub, members
WHERE members.userid = forum_sub.userid AND forum_sub.forum_id = 1
ORDER BY forum_sub.timestamp DESC
which displays the following
----------------------------------------------------------------------
sub_id | forum_id | title | text | url | userid | first_name | views |
----------------------------------------------------------------------
20 | 1 | test | test |test | 1001 | JOhn | 123 |
----------------------------------------------------------------------
1 | 1 | test | test |test | 1002 | Pete | 23 |
----------------------------------------------------------------------
10 | 1 | test | test |test | 1003 | Harry | 34 |
----------------------------------------------------------------------
But now I want to join the above sub_id to another table called forum_topics and count how many of the same sub_id's there are and bring in that value
for example I could use
SELECT sub_id, COUNT(sub_id) as topics FROM forum_topics GROUP BY sub_id
-----------------
|sub_id | topics|
---------------
| 1 | 4 |
-----------------
| 10 | 3 |
-----------------
| 20 | 5 |
-----------------
My question is how can I join those 2 queries so I get something like this
----------------------------------------------------------------------------
sub_id | forum_id | title | text | url | userid | first_name | views | count|
-----------------------------------------------------------------------------
20 | 1 | test | test |test | 1001 | JOhn | 123 | 5 |
-----------------------------------------------------------------------------
1 | 1 | test | test |test | 1002 | Pete | 23 | 4 |
-----------------------------------------------------------------------------
10 | 1 | test | test |test | 1003 | Harry | 34 | 3 |
-----------------------------------------------------------------------------
Any help would be great, I know I need to use a subquery but I've been stuck on this nearly all day with no luck
First avoid SELECT DISTINCT when ever possible. It is evil. It will hide cross joins etc that you have in your query. From this query it is hard to tell what exactly your are doing.
However to include the count you have a couple of options:
One would be to do a sub select in the query:
SELECT forum_sub.sub_id, forum_id, title, text, url, forum_sub.userid,
members.first_name, views , (SELECT COUNT(sub_id) as topics FROM forum_topics WHERE sub_id = forum_sub.sub_id) count
FROM forum_sub, members
WHERE members.userid = forum_sub.userid AND forum_sub.forum_id = 1
ORDER BY forum_sub.timestamp DESC
Another would be to actually join to the sub query you created:
SELECT forum_sub.sub_id, forum_id, title, text, url, forum_sub.userid,
members.first_name, views, counts.topics
FROM forum_sub, members
JOIN (SELECT sub_id, COUNT(sub_id) as topics FROM forum_topics GROUP BY sub_id) counts ON (counts.sub_id = forum_sub.sub_id)
WHERE members.userid = forum_sub.userid AND forum_sub.forum_id = 1
ORDER BY forum_sub.timestamp DESC
You should also look at joins instead of selecting multiple tables in your from
SELECT forum_sub.sub_id, forum_id, title, text, url, forum_sub.userid,
members.first_name, views, counts.topics
FROM forum_sub
JOIN members ON (members.userid = forum_sub.userid)
JOIN (SELECT sub_id, COUNT(sub_id) as topics FROM forum_topics GROUP BY sub_id) counts ON (counts.sub_id = forum_sub.sub_id)
WHERE forum_sub.forum_id = 1
ORDER BY forum_sub.timestamp DESC
Try
group by sub_id
at the end of your second query instead of WHERE.
Then join it to the other table.