job table
1.id
2.status = 'active'
3.name
repair table
1.repair id
2.job_id
3.process = 'yes|no'
4.status = '1|2'
job table
id name status
1 test active
2 check active
repair table
repair_id job_id process status
1 1 no 2
2 1 no 1
3 1 yes 2
4 2 no 1
5 2 no 2
here i need to show data which ( process != 'yes' and repair_status != 2 ) group by job_id
i need result after query
---------------------------------------------
job_id name( job.name ) status( job.status )
------------------------------------------------
2 check active
In order to get the results that you specify, you mean that process is not yes for any row for the job_id. And then that at least one row has a status <> 2. That would be:
select j.job_id, j.name, j.status
from repair r join
job j
on r.job_id = r.id
group by j.job_id, j.name, j.status
having max(process) = 'no' and
min(repair_status) = 1;
If you want jobs for which no repair exists with process = 'yes' and status = 2, you can use not exists:
select j.*
from jobs j
where not exists (
select 1
from repair r
where r.job_id = j.id and r.process = 'yes' and r.status = 2
)
Related
I have written the following query where in the rows are returned using order by clause:
SELECT host.hostname,
cb.orderId,
cb.status,
cb.chefbook_name AS Heading,
(SELECT log_message
FROM chefbookrun rr
WHERE rr.chefbook_id = c.id
ORDER BY id DESC
LIMIT 1) AS Detail
FROM host
INNER JOIN host_infl hif
ON host.vc_server_id = hif.vc_server_id
INNER JOIN chefcookbook cb
ON hif.id = cb.host_id
WHERE host.hostname REGEXP 'abc'
ORDER BY cb.orderId;
There are few different types of output as shown below:
hostname orderId status Heading Detail
abc.com 3 30 HeadingA Details1
abc.com 5 40 HeadingB Details2
... more rows
hostname orderId status Heading Detail
cde.com 3 40 HeadingA Details1
cde.com 5 30 HeadingB Details2
... more rows
hostname orderId status Heading Detail
efg.com 3 50 HeadingA Details1
efg.com 5 30 HeadingB Details2
... more rows
I want to perform calculation on status of first returned row as below:
1) If `status is 30` then show status as `Finished`. Also `Heading` and `Detail` should be empty.
2) If `status is 40` or `status is 50` then show status as `Error`. `Heading` and `Detail` should show as such.
Desired output is as follows:
hostname orderId status Heading Detail
abc.com 3 Finished
hostname orderId status Heading Detail
cde.com 3 Error HeadingA Details1
hostname orderId status Heading Detail
efg.com 3 Error HeadingA Details1
SELECT host.hostname,orderId,
CASE WHEN status = 30 THEN 'Finished' ELSE 'Error' END 'status',
CASE WHEN status = 30 THEN '' ELSE Heading END 'Heading',
CASE WHEN status = 30 THEN '' ELSE Detail END 'Detail'
FROM
(
SELECT host.hostname,
cb.orderId,
cb.status,
cb.chefbook_name AS Heading,
(
SELECT log_message
FROM chefbookrun rr
WHERE rr.chefbook_id = c.id
ORDER BY id DESC
LIMIT 1
) AS Detail
FROM host
INNER JOIN host_infl hif ON host.vc_server_id = hif.vc_server_id
INNER JOIN chefcookbook cb ON hif.id = cb.host_id
WHERE host.hostname REGEXP 'abc'
ORDER BY cb.orderId
) AS temp
GROUP BY hostname;
My problem is simple: I want to list everything from my "form" table and if there aren't any matches to this "form" in the "outstanding" table, then this row should be also listed only with NULL in the PAYED_GROSS_AMOUNT column (the "outstanding" table is used for example for this column). Right now with this query all I get are the "form" matches, which have also matching entries in the "outstanding" table:
SELECT
`f`.`ID` AS `ID`,
`f`.`FORM_NR` AS `form_nr`,
`f`.`DELIVERY_DATE` AS `delivery_date`,
`f`.`FORM_DATE` AS `form_date`,
`f`.`PAYMENT_DATE` AS `payment_date`,
MAX(`os`.`PAYED_DATE`) AS `payed_date`,
`fi`.`GROSS_MONEY` AS `gross_money`,
`fi`.`NET_PRICE` AS `net_price`,
ifnull(SUM(`os`.`PAYED_GROSS_AMOUNT`), 0) AS `payed_gross_amount`,
ifnull((`fi`.`GROSS_MONEY`
- SUM(`os`.`PAYED_GROSS_AMOUNT`)),
`fi`.`GROSS_MONEY`) AS `remaining_amount`
FROM `form` `f`
LEFT JOIN `outstanding` `os` ON `f`.`ID` = `os`.`INVOICE_ID`,
(SELECT form_id AS `FORM_ID`,
SUM(gross_money) AS `GROSS_MONEY`,
SUM(net_price) AS `NET_PRICE`
FROM form_item
GROUP BY form_id) fi
WHERE `f`.SUBTYPE <> 3
AND `fi`.FORM_ID = `f`.ID
AND `f`.STATUS = 2
AND `f`.DIRECTION = 1
AND `os`.DELETED <> 'deleted'
AND (`f`.PAYMENT_TYPE = 2 OR `f`.PAYMENT_TYPE = 4)
AND `f`.FORM_TYPE = 'Invoice'
AND `f`.deleted <> 'deleted'
GROUP BY `f`.`ID`,
`fi`.`form_id`
ORDER BY `f`.`FORM_DATE` DESC;
I also tried with LEFT OUTER JOIN but with no luck :(
Thank you!
EDIT:
Query simplified as possible (you can ignore the WHERE clauses in the end)
Expected result:
form table:
ID FORM_NR ...
1 2019/1
2 2019/2
3 2019/4
4 2019/7
...
outstanding table:
INVOICE_ID PAYED_DATE PAYED_GROSS_AMOUNT ...
2 2019-02-05 100
3 2019-02-06 200
...
Result:
FORM_NR FORM_DATE ... PAYED_DATE PAYED_GROSS_AMOUNT
2019/1 2019-02-01 null 0
2019/2 2019-02-02 2019-02-05 100
2019/4 2019-02-03 2019-02-06 200
2019/7 2019-02-04 null 0
...
PAYED_GROSS_AMOUNT is because of the IFNULL method 0 and not NULL.
Use NOT EXISTS. Something like this:
select . . .
from form f
where <conditions on form> and
not exists (select 1
from outstanding o
where o.form_item = f.id and
<conditions on outstanding>
);
I need to select random user_id from "user" table, and completely exclude any user_id if current user have any "ongoing" battles with him battles.status
Query:
SELECT user.id
FROM user
LEFT JOIN battles b ON b.uid = user.id AND b.status <> 'ongoing'
WHERE user.id <> 1
ORDER BY RAND( )
LIMIT 1
But the query is not sufficient, because a user can have multiple battles with specific other users, one of them "ongoing" and the others "finished",
My query should select users from the "finished" row.
Tables structure:
user table:
id name
1 John
2 Sarah
3 Jack
4 Andy
5 Rio
battles table:
id uid uid2 status
1 1 2 finished
2 1 2 ongoing
3 2 3 ongoing
4 1 4 finished
5 3 5 finished
If "my" id = "1",
I want to completely exclude any user I have ongoing battle with him, like "2" in the above case and accept all other ids (i.e.3,4 and 5)
You probably want something along the lines of this:
SELECT foe.*
-- Select yourself and join all other users to find potential foes
FROM `user` AS me
INNER JOIN `user` AS foe
ON (me.id <> foe.id)
-- Here we select the active user
WHERE me.`id` = 1
-- Now we exclude foes we have ongoing battles with
-- (your id could be in either uid or uid2)
AND foe.`id` NOT IN (
SELECT `uid` FROM `battles`
WHERE `uid2` = me.`id` AND `status` = 'ongoing'
UNION ALL
SELECT `uid2` FROM `battles`
WHERE `uid` = me.`id` AND `status` = 'ongoing'
);
This will return a list of users which you do not currently have ongoing battles with. You can customise this to return just one of them using LIMIT and random ordering like in your example.
SQL Fiddle
http://sqlfiddle.com/#!2/1c5fc3/1
I am trying to create simple messaging system, but I am having trouble with the desired results from the SQL queries.
Here are the tables I have; I am trying to get INBOX data..
INBOX Definiton for this problem:
This should be threaded display in inbox, ie. google mail, but only to show the last message in that thread with the user who originaly created the thread and the last user who replied in the thread, if the last user is the same user that created the thread and there are no replies in beetween the message doesnt belog in inbox.
TABLES:
THREAD
id_thread
id_last_message
id_user_inital
id_user_last
THREAD_USERS
id
id_thread
id_user
THREAD_MESSAGES
id_thread_messages
id_user_sender
id_thread
datetime
subject
body
MESSAGE_STATUS
id_messsage_status
id_thread_messages
id_user
status
datetime
My logic is:
once a message has been sent
THREAD
id_thread id_last_message id_user_inital id_user_last
1 1 1 1
THREAD_USERS
id id_thread id_user
1 1 1
2 1 2
THEREAD_MESSAGES
id_thread_messages id_user_sender id_thread datetime subject body
1 1 1 07.09.2014 16:02 'title' 'text message'
MESSAGE_STATUS
id_message_status id_thread_messages id_user status datetime
1 1 1 4 07.09.2014 16:02
2 1 2 1 07.09.2014 16:02
Lets say status can be
0 = deleted (do not show at all)
1 = new (show only to user that is on the receiving end)
2 = read (this status will be shown to all users in the thread)
3 = replied (show only to user that makes this action)
4 = sent (show only to user that makes this action)
Query :
SELECT *
FROM thread
JOIN thread_users
ON thread.id_thread = thread_users.id_thread
JOIN thread_messages
ON thread.id_thread = thread_messages.id_thread
JOIN message_status
ON thread_messages.id_thread_messages = message_status.id_thread_messages
WHERE
thread_users.id_user = 2
AND message_status.status != 0
AND message_status.status != 4
AND thread.id_user_last != message_status.id_user
sample data
THREAD
id_thread id_last_message id_user_inital id_user_last
1 4 1 2
2 2 3 3
3 3 4 4
THREAD_USERS
id id_thread id_user
1 1 1
2 1 2
3 2 3
4 2 2
5 3 4
6 3 2
THEREAD_MESSAGES
id_thread_messages id_user_sender id_thread datetime subject body
1 1 1 07.09.2014 16:02 'title' 'text message'
2 3 2 07.09.2014 16:05 'hey two' 'foo'
3 4 2 07.09.2014 16:07 'hey two' 'bar'
4 2 1 07.09.2014 16:10 'title' 'replay on 1st'
MESSAGE_STATUS
id_message_status id_thread_messages id_user status datetime
1 1 1 4 07.09.2014 16:02
2 1 2 1 07.09.2014 16:02
3 2 3 4 07.09.2014 16:05
4 2 2 1 07.09.2014 16:05
5 3 4 4 07.09.2014 16:07
6 3 2 1 07.09.2014 16:07
7 4 2 4 07.09.2014 16:10
8 4 1 1 07.09.2014 16:10
How would you extract INBOX data from this situation, as I am spinning in circles for hours and can't quite get what I am doing wrong.
Thank you.
Updated solution after taking into account explanations for message status:
SELECT DISTINCT t.*, tm.* , ms.*
FROM thread t
-- tm should be last message
INNER JOIN thread_messages tm ON t.id_thread = tm.id_thread
INNER JOIN message_status ms ON (ms.id_thread_messages = tm.id_thread_messages)AND
(ms.id_user=2)AND
(ms.status!=0)
-- try to find message after tm, and then in WHERE filter only those cases where there is no message after tm
LEFT JOIN thread_messages tm_next
INNER JOIN message_status ms_next ON (ms_next.id_thread_messages = tm_next.id_thread_messages)AND
(ms_next.id_user=2)AND
(ms_next.status!=0)
ON (t.id_thread = tm_next.id_thread)and
(tm_next.datetime>tm.datetime)
LEFT JOIN thread_messages tm_other
INNER JOIN message_status ms_other ON (ms_other.id_thread_messages = tm_other.id_thread_messages)AND
(ms_other.id_user=2)AND
(ms_other.status!=0)
ON (t.id_thread = tm_other.id_thread)and
(tm_other.id_thread_messages!=tm.id_thread_messages)and
(tm_other.id_user_sender!=2)
WHERE
-- ensure tm is last message in thread
(tm_next.id_thread is null)and
(
-- there is a non deleted message from another user in current thread
(tm_other.id_thread_messages is not null)or
-- last message is not from current user
(tm.id_user_sender!=2)
)
SqlFiddle is here.
Let me know is this working for you.
i think this is the solution that you are looking for
SELECT * FROM thread
JOIN thread_users ON thread.id_thread = thread_users.id_thread
JOIN thread_messages ON thread.id_thread = thread_messages.id_thread
JOIN message_status ON thread_messages.id_thread_messages = message_status.id_thread_messages
WHERE thread_users.id_user = 2
AND thread_users.id_user = message_status.id_user
AND message_status.status != 0
AND message_status.status != 4
AND thread.id_user_last != message_status.id_user
Now with the description of what INBOX means I suggest you rely heavily on EXISTS clause in your query. Here is just an example of how it can look like:
SELECT *
FROM thread t INNER JOIN
thread_messages tm ON t.id_thread = tm.id_thread
WHERE
EXISTS ( -- User is in the thread.
SELECT * FROM thread_users tu
WHERE t.id_thread = tu.id_thread AND tu.id_user = 2
)
AND NOT EXISTS ( -- Exclude earlier messages for thread.
SELECT * FROM thread_messages WHERE
tm.id_thread = id_thread AND datetime > tm.datetime
AND EXISTS (-- Exclude deleted messages here
SELECT * FROM message_status
WHERE thread_messages.id_thread_messages = id_thread_messages
AND status != 0
AND status != 4
)
)
AND EXISTS ( -- Include messages that were not deleted or send to self.
SELECT * FROM message_status
WHERE tm.id_thread_messages = id_thread_messages
AND status != 0
AND status != 4
AND t.id_user_last != id_user -- not sure what is this for
)
AND EXISTS ( -- Include threads with messages from several users
SELECT * FROM thread_messages
WHERE tm.id_thread = id_thread
AND tm.id_user_sender != t.id_user_inital)
http://sqlfiddle.com/#!2/1c5fc3/39
In My application I want to display all my friends and no of cheque given and received
Table Transaction Table Friends
---------------------------- -----------------------------
id given_id rev_id amt id who_id whom_id who_name
----------------------------- -------------------------------
1 2 1 1k 1 1 2 sss
2 2 3 1k 2 3 2 fff
3. 3 2 2k 3 4 1 eee
4 1 2 2k 4 2 1 iii
----------------------------- ------------------------------
Result whom_id=2 name=iii -> Friends (sss,fff)
=> sss gives totally 1 cheque and
sss receives totally 1 cheque and
fff gives 1 cheque and
fff receives 1 cheque and
I tried This one..
SELECT
p.who_id,
p.who_name,
COUNT( r1.give_id ) ,
COUNT( r1.rec_id )
FROM
friends p
LEFT JOIN Transaction r1
ON p.who_id = r1.give_id OR p.who_id = r1.rec_id
WHERE
p.whom_id = 1
GROUP BY p.who_id
Please provide me the best way to do this....
You can do it like this
SELECT
f.who_name,
count(t.given_id) GivenTotal,
count(lt.rev_id) as RecievedTotal
from friends as f
left join transaction as t
on t.given_id = f.who_id
left join transaction as lt
on lt.rev_id = f.who_id
where f.whom_id = 2
group by t.given_id
Demo
Output
who_name | GivenTotal | RecievedTotal
----------------------------------
sss | 1 | 1
fff | 1 | 1
try this,
select
id,
count(given_id) as given,
count(rev_id) as reveive
from Friends
GROUP BY id;
and if you whant the difference between the two amounts try this
select
id,
count(given_id) as given,
count(rev_id) as reveive,
given-receive as diff
from Friends
GROUP BY id;
You can use HAVING with group by ,
instead
WHERE p.whom_id = 1
There are two ways to do this, both involve joining on the Transactions table twice.
You can use subqueries:
SELECT f.who_id,
f.who_name,
t1.TotalGiven,
t2.TotalRev
FROM friends f
LEFT JOIN
(
select count(t.given_id) TotalGiven, t.given_id
from Transactions t
group by t.given_id
) t1
ON f.who_id = t1.given_id
LEFT JOIN
(
select count(t.rev_id) TotalRev, t.rev_id
from Transactions t
group by t.rev_id
) t2
ON f.who_id = t2.rev_id
where f.whom_id = 2;
See SQL Fiddle with Demo.
Or you can just use a join with no subquery:
select f.who_id,
f.who_name,
count(t1.given_id) TotalGiven,
count(t2.rev_id) TotalRev
FROM friends f
LEFT JOIN Transactions t1
ON f.who_id = t1.given_id
LEFT JOIN Transactions t2
ON f.who_id = t2.rev_id
where f.whom_id = 2
group by f.who_id, f.who_name
See SQL Fiddle with Demo
Finally I got the answer,
SELECT
p.who_id, p.who_name, COUNT( r1.give_id ) , COUNT( r2.rec_id )
FROM
friends p
LEFT JOIN Transaction r1 ON p.who_id = r1.give_id
LEFT JOIN Transaction r2 on p.who_id = r2.rec_id
WHERE
p.whom_id = 1
GROUP BY p.who_id