query for records that do not exist - mysql

SELECT today.status, GROUP_CONCAT(tomorrow.work_order order by line), today.code, today.events
FROM today LEFT JOIN tomorrow
ON today.code = tomorrow.code
WHERE today.status like '1%' or
(today.status like '3%' and tomorrow.work_ordertext is null)
GROUP BY today.code
I am having issues with the 'tomorrow.work_ordertext is null' statement. tomorrow.code and tomorrow.work_ordertext may not even exist in the table, so I am guessing it shouldn't really be a null statement. I am looking for a way to pull rows from the today table if no records exists on the tomorrow table once the status is like 3 in the today table. Sorry if it sounds confusing.

SELECT today.status, GROUP_CONCAT(tomorrow.work_order order by line), today.code, today.events
FROM today LEFT JOIN tomorrow
ON today.code = tomorrow.code
WHERE today.status = 1 or
(today.status = 3 and isnull( tomorrow.work_ordertext ))
GROUP BY today.code
I took out the like for the status as it will match 1, 10, 1b, 1somethingweird.

Related

Get Records From Table 1, Comparing With Multiple Records From Table 2

I have 2 tables (users and usages)
USERS TABLE
username usage
a 32
b 5
c 5
USAGES TABLE
username usage_added
a 7
b 7
c 7
a 30
I want to get all items from USERS table, that have USAGE BIGGER than X (in this case, let's say X is 30) AND if either NO RECORDS are found with the same username in USAGES TABLE or if the usage_added for this username in USAGES TABLE are SMALLER than X (30 in our case)
So in this case, it should return no records. I have a codeigniter query
$this->db->select('users.username');
$this->db->from('users');
$this->db->join('usages', 'usages.username = users.username','left');
$this->db->where("(usages.email is NULL OR (usages.usage_added<30 AND usages.username=users.username))", NULL, FALSE);
$this->db->where("users.usage>30", NULL, FALSE);
By using above query, I still get "username a" returned.
Normally it should not return user A, because user a already has date 30 added. But it seems it compares to first record (a=7) and it says a<30 and it shows it again.
I hope it makes sense and somebody can help.
Written SQL Server syntax, this query should work for you:
DECLARE #usage_limit int = 30;
SELECT A.username
FROM users as A
LEFT OUTER JOIN
(
SELECT username,
usage_added = sum(usage_added)
FROM usages
GROUP BY
username
) as B
ON A.username = B.username
WHERE A.usage > #usage_limit
AND (B.username is null OR B.usage_added < #usage_limit)
This returns no records.
Hope this helps!
You seem to be describing logic like this:
select u.*
from users u
where u.usage > 30 or
not exists (select 1
from usages us
where us.username = u.username and
us.usage > 30
);
You should replace the 30 with a parameter if it varies.

filed showing null value when joining table

below is my query
select C.cName,DATE_FORMAT(CT.dTransDate,'%d-%M-%Y') as dTransDate,
(c.nOpBalance+IFNULL(CT.nAmount,0)) AS DrAMount,IFNULL(CTR.nAmount,0) AS
CrAMount,((c.nOpBalance+IFNULL(CT.nAmount,0))-IFNULL(CTR.nAmount,0)) AS
Balance,CT.cTransRefType,CT.cRemarks,cinfo.cCompanyName,cinfo.caddress1,cinfo.cP
honeOffice,cinfo.cMobileNo,cinfo.cEmailID,cinfo.cWebsite from Customer
C LEFT JOIN Client_Transaction CT ON CT.nClientPk = C.nCustomerPk AND
CT.cTransRefType='PAYMENT' AND CT.cClientType='CUSTOMER' AND CT.dTransDate
between '' AND '' LEFT JOIN Client_Transaction CTR ON CTR.nClientPk =
C.nCustomerPk AND CTR.cTransRefType='RECEIPT' AND
CTR.cClientType='CUSTOMER' AND CTR.dTransDate between '2015-05-01' AND
'2015-05-29' LEFT JOIN companyinfo cinfo ON cinfo.cCompanyName like
'%Fal%' Where C.nCustomerPk = 4 Order By dTransDate
it's showing all value but dTransDate ,cTransRefType,cRemarks, showing null.
One obvious thing jumps out at us:
CT.dTransDate BETWEEN '' AND ''
^^ ^^
Another thing that jumps out at us is that there's a semi-Cartesian join between rows from CT and rows from CTR. If 5 rows are returned from CT for a given customer, and 5 rows are returned from CTR, that's going to produce a total of 5*5 = 25 rows. That just doesn't seem like a resultset that you'd really want returned.
Also, if more than one row is returned from cinfo, that's also going to cause another semi-Cartesian join. If there's two rows returned from cinfo, the total number or rows in the resultset will be doubled. It's valid to do that in SQL, but this is an unusual pattern.
The calculation of the balance is also very strange. For each row, the nAmount is added/subtracted from opening balance. On the next row, the same thing, on the original opening balance. There's nothing invalid SQL-wise with doing that, but the result being returned just seems bizarre. (It seems much more likely that you'd want to show a running balance, with each transaction.)
Another thing that jumps out at us is that you are ordering the rows by a string representation of a DATE, with the day as the leading portion. (As long as all the rows have date values in the same year and month, that will probably work, but it just seems bizarre that we wouldn't sort on the DATE value, or a canonical string representation.
I strongly suspect that you want to run a query that's more like this. (This doesn't do a "running balance" calculation. It does return the 'PAYMENT' and 'RECEIPT' rows as individual rows, without producing a semi-Cartesian result.
SELECT c.cName
, DATE_FORMAT(t.dTransDate,'%d-%M-%Y') AS dTransDate
, C.nOpBalance
, IF(t.cTransRefType='PAYMENT',IFNULL(t.nAmount,0),0) AS DrAMount
, IF(t.cTransRefType='RECEIPT',IFNULL(t.nAmount,0),0) AS CrAMount
, t.cTransRefType
, t.cRemarks
, ci.*
FROM Customer c
LEFT
JOIN Client_Transaction t
ON t.nClientPk = c.nCustomerPk
AND t.cClientType = 'CUSTOMER'
AND t.dTransDate >= '2015-05-01'
AND t.dTransDate <= '2015-05-29'
AND t.cTransRefType IN ('PAYMENT','RECEIPT')
CROSS
JOIN ( SELECT cinfo.cCompanyName
, cinfo.caddress1
, cinfo.cPhoneOffice
, cinfo.cMobileNo
, cinfo.cEmailID
, cinfo.cWebsite
FROM companyinfo cinfo
WHERE cinfo.cCompanyName LIKE '%Fal%'
ORDER BY cinfo.cCompanyName
LIMIT 1
) ci
WHERE c.nCustomerPk = 4
ORDER BY t.dTransDate, t.cTransRefTpye, t.id

Getting the latest 'role-switch' timestamp from a messages table

Problem
I am looking at trying to get the lowest timestamp (earliest) after the 'side' has changed in a ticket conversation, to see how long it has been since the first reply to the latest message.
Example:
A (10:00) : Hello
A (10:05) : How are you?
B (10:06) : I'm fine, thank you
B (10:08) : How about you?
A (10:10) : I'm fine too, thank you <------
A (10:15) : I have to go now, see you around!
Now what I am looking for is the timestamp of the message indicated by the arrow. The first message after the 'side' of the conversation changed, in this case from user to support.
Example data from table "messages":
mid conv_id uid created_at message type
2750 1 3941 1341470051 Hello support
3615 1 3941 1342186946 How are you? support
4964 1 2210 1343588022 I'm fine, thank you user
4965 1 2210 1343588129 How about you? user
5704 1 3941 1344258743 I'm fine too, thank you support
5706 1 3941 1344258943 I have to go now, see you around! support
What I have tried so far:
select
n.nid AS `node_id`,
(
SELECT m_inner.created_at
FROM messages m_inner
WHERE m_inner.mid = messages.mid AND
CASE
WHEN MAX(m_support.created_at) < MAX(m_user.created_at) THEN -- latest reply from user
m_support.created_at
ELSE
m_user.created_at
END <= m_inner.created_at
ORDER BY messages.created_at ASC
LIMIT 0,1
) AS `latest_role_switch_timestamp`
from
node n
left join messages m on n.nid = messages.nid
left join messages m_user on n.nid = m_user.nid and m_user.type = 'user'
left join messages m_support on n.nid = m_support.nid and m_support.type = 'support'
GROUP BY messages.type, messages.nid
ORDER BY messages.nid, messages.created_at DESC
Preferred result:
node_id latest_role_switch_timestamp
1 1344258743
But this has not yielded any results for the subquery. Am I looking in the right direction or should I try something else? I don't know if this would be possible in mysql.
Also this uses a subquery, which, for performance reasons, is not ideal, considering this query will probably be used in overviews, meaning it would have to run that subquery for every message in the overview.
If you require any more information, please tell me, as I am at my wit's end
Join the table to a max-date summary of itself to get the messages of the last block, then use mysql's special group-by support to pick the first row from those for each conversation:
select * from (
select * from (
select m.*
from messages m
join (
select conv_id, type, max(created_at) last_created
from messages
group by 1,2) x
on x.conv_id = m.conv_id
and x.type != m.type
and x.last_created < m.created_at) y
order by created_at) z
group by conv_id
This returns the whole row that was the first message of the last block.
See SQLFiddle.
Performance will be pretty good, because there are no correlated subqueries.

SQL SUM issues with joins

I got a quite complex query (at least for me).
I want to create a list of users that are ready to be paid. There are 2 conditions that need to be met: order status should be 3 and the total should be more then 50. Currently I got this query (generated with Codeingiter active record):
SELECT `services_payments`.`consultant_id`
, `consultant_userdata`.`iban`
, `consultant_userdata`.`kvk`, `consultant_userdata`.`bic`
, `consultant_userdata`.`bankname`
, SUM(`services_payments`.`amount`) AS amount
FROM (`services_payments`)
JOIN `consultant_userdata`
ON `consultant_userdata`.`user_id` = `services_payments`.`consultant_id`
JOIN `services`
ON `services`.`id` = `services_payments`.`service_id`
WHERE `services`.`status` = 3
AND `services_payments`.`paid` = 0
HAVING `amount` > 50
The services_payments table contains the commissions, consultant_userdata contains the userdata and services keeps the order data. The current query only gives me 1 result while I'm expecting 4 results.
Could someone please tell me what I'm doing wrong and what would be the solution?
For ActiveRecord, rsanchez' answer would be more of
$this->db->group_by('services_payments.consultant_id, consultant_userdata.iban, consultant_userdata.kvk, consultant_userdata.bic, consultant_userdata.bankname');

Why does this query returns no result?

I have two Tables, the table reseau_stream has different information about my a user post. A user can share the post of someone else. Table reseau_share makes that connexion (you have the detail of both table below). Now, if a user share someone else post, I have to order my query using the datetime of reseau_share.
I don't have alot of MySQL skills, but with some help, I finally ended up with the query below. It is working only if reseau_share has a row in it. If reseau_share is empty, the query return 0 result. I really don't understand why. Can anyone identify why ? Cheers.
Table reseau_stream
id user_id content datetime
1 100 Lorem Ipsum1 2013-03-04 19:35:02
2 100 Lorem Ipsum2 2013-03-04 12:35:02
Table reseau_share
id user_id target_id stream_id datetime
-------------------- EMPTY ------------------------
The query
SELECT reseau_stream.id,
reseau_stream.user_id,
reseau_stream.content,
IF(reseau_stream.user_id = 100, reseau_stream.datetime, reseau_share.datetime) as datetime
FROM reseau_stream, reseau_share
WHERE reseau_stream.id
IN (
SELECT id
FROM reseau_stream
WHERE user_id = 100
UNION
SELECT stream_id
FROM reseau_share
WHERE user_id = 100
) ORDER BY datetime DESC;
Basically it looks like you need a LEFT JOIN on reseau_share. Right now you have a FULL OUTER JOIN, which (a) is causing the zero rows as #diegoperini has pointed out and (b) probably isn't what you really want. It's unclear which column relates the two tables. I'll guess it's user_id:
SELECT
reseau_stream.id,
reseau_stream.user_id,
reseau_stream.content,
IF(reseau_stream.user_id = 100, reseau_stream.datetime, reseau_share.datetime) as datetime
FROM reseau_stream
LEFT JOIN reseau_share ON reseau_stream.user_id = reseau_share.user_id
WHERE reseau_stream.id
IN (
SELECT id
FROM reseau_stream
WHERE user_id = 100
UNION
SELECT stream_id -- or whatever
FROM reseau_share
WHERE user_id = 100
)
ORDER BY datetime DESC;
Cartesian product of a non empty set with an empty set is an empty set.
Multiple tables in a FROM statement uses above rule to join two tables which ends up with 0 results in your case.