Returning Value where no rows returned - mysql

Table one includes delivery_id
Table two includes the name of store where delivery originated
Table two includes delivery_id and delivery_events
I'm trying to find specific delivery_id(s) where there is no delivery_event. The issue is that if there is no delivery_event, there is no data stored in table MAINDB_DELIVERY_EVENT.
What would be the best query to pull deliveries by date where there is no delivery_event - EXTRA would be to have that pull in as a separate column called Event_Status with value failed where there is no corresponding delivery event?
Here's where I am now which is not returning anything:
select MO.delivery_id,
DS.name,
MO.created_at
from MAINDB_ORDER MO
join maindb_store DS on DS.id = MO.store_id
where exists (
select ISNULL (MO.delivery_id
from MAINDB_DELIVERY_EVENT dwe
where dwe.id is null)
and MO.created_at between '2019-01-01' and '2019-12-31'
limit 1

Is this what you want?
select MO.delivery_id, DS.name, MO.created_at,
exists (select 1
from MAINDB_DELIVERY_EVENT dwe
where dwe.delivery_id = mo.delivery_id
) as delivery_flag
from MAINDB_ORDER MO join
maindb_store DS
on DS.id = MO.store_id
where MO.created_at between '2019-01-01' and '2019-12-31'
limit 1;
I am guessing that delivery_id is what links the tables. However, that is speculation because it is not clear from your question what links the tables.

You might try the LEFT JOIN ... IS NULL pattern. This will find items in your MAINDB_ORDER table that don't have any matches in MAINDB_DELIVERY_EVENT via the delivery_id column.
SELECT MO.delivery_id
FROM MAINDB_ORDER MO
LEFT JOIN MAINDB_DELIVERY_EVENT MDE ON MO.delivery_id = MDE.delivery_id
WHERE MDE.delivery_id IS NULL
This gets you the delivery_id values present in MO and absent in MDE. You can add your other WHERE criteria as you wish.
This is equivalent to
SELECT MO.delivery_id
FROM MAINDB_ORDER MO
WHERE MO.delivery_id NOT IN (
SELECT delivery_id FROM MAINDB_DELIVERY_EVENT
)
Again, you should add your WHERE clauses as needed.

Related

query make a count to 1 which does not satistfy the condition

i have a two table i want to know the number of person who are all assigned to project in each sector
CREATE TABLE first1( a int,projectname varchar(20));
INSERT INTO first1 VALUES
(1001,'crm'),
(1002,'iic'),
(1003,'abc'),
(1004,'sifty bank');
CREATE TABLE diff(b int,name varchar(20),p_id int );
INSERT INTO diff VALUES
(101,'priya',1001),
(102,'divya',1002),
(103,'sidhu',null),
(104,'shiva',null),
(105,'surya',1002);
Query:
select first1.projectname,count(*) from first1 left join diff on first1.a=diff.p_id group by
first1.projectname;
The output of this code is:
abc|1
crm|1
iic|2
sifty bank|1
The expected output is :
abc|0
crm|1
iic|2
sifty bank|0
The problem is count(*); it counts how many rows there are in each group - A project without any person assigned still counts as 1. Instead, you need to count() something from the left table, so null values are not taken into account:
select f.projectname, count(d.p_id) as cnt_diff
from first1 f
left join diff d on f.a = d.p_id
group by f.projectname;
Note that you can get the same result with a subquery:
select f.projectname,
(select count(*) from diff d where d.p_id = f.a) as cnt_diff
from first1 f

Sorting data from a join chronologically to get most recent entry

I have 3 Database Tables:
OpenROHeader
OpenROData
OpenRONotes
Header & Data are updated (overwritten) hourly while Notes are added manually and linked via a field "RO_Number"
What I want the SQL to do is retrieve the most current "Notes" (by 'date_updated')
SELECT file_date, rod.id as id, key_id, key_name, key_value, DATE_FORMAT(expected_close_date , '%d/%m/%y' ) as expected_close_date, wty_dept
FROM OpenROHeader roh
JOIN OpenROData rod ON roh.id=rod.header_id
LEFT JOIN OpenRONotes ron ON rod.key_value=ron.ro_number
WHERE roh.customer_id='193'
GROUP BY key_id, key_name
There are 2 entries in Notes table - I want the most recent:
id, customer_id, ro_number, expected_close_date, advisor_notes, wty_dept, date_updated
4059, 193, 'S117986', NULL, 'WTY_ON<br>- S.W.', 'on', '2018-09-24 05:02:45'
4060, 193, 'S117986', NULL, 'WTY_OFF<br>- S.A.', NULL, '2018-09-24 05:03:24'
I want it to return data (last 2 columns) in SELECT from row with id 4060 NOT 4059
http://sqlfiddle.com/#!9/f00326/1/0
But instead of returning most current 'wty_dept' (NULL) from 2018-09-24 05:03:24
My SQL statement is returning the previous entry 'on' from 2018-09-24 05:02:45 (older)
How can I sort a join to return most recent data
put desc after group by clouse
for example-
SELECT * from student GROUP BY section desc;
it will g
I don't think you need to sort, just make sure there is not a later comment. I've made assumptions about how we look up the notes, but assuming I have it correct, this should do it for you (UPDATED after I think I understood your requirements!)
SELECT file_date, advisor_notes, rod.id as id, key_id, key_name, key_value, DATE_FORMAT(expected_close_date , '%d/%m/%y' ) as expected_close_date, wty_dept
FROM OpenROHeader roh
JOIN OpenROData rod ON roh.id=rod.header_id
LEFT JOIN OpenRONotes ron ON rod.key_value=ron.ro_number
WHERE roh.customer_id='193'
and not exists (select * from OpenRONotes ron2 where rod.key_value=ron2.ro_number and ron2.date_updated>ron.date_updated)
You can get the most recent column from join of three tables as:
SELECT file_date, rod_id AS id, key_id, key_name, key_value, DATE_FORMAT(expected_close_date , '%d/%m/%y' ) AS expected_close_date, wty_dept
FROM OpenROHeader roh
RIGHT OUTER JOIN
(SELECT rod.id rod_id ,key_id,key_name ,key_value ,expected_close_date ,wty_dept ,header_id,date_updated
FROM OpenROData rod
RIGHT OUTER JOIN OpenRONotes ron
ON rod.key_value=ron.ro_number
ORDER BY ron.date_updated ) tab
ON roh.id=header_id WHERE 1=1 AND
roh.customer_id='193'
ORDER BY date_updated DESC LIMIT 1;
The above query returned the most recent records with column wty_dept as NULL.
Check this and enjoy coding :) !!

Find errors in a sequence

I have an activity changelog of officers that become active/inactive.
OfficerID ChangeTo ChangeDate
1 active 2017-05-01
1 active 2017-05-02
1 inactive 2017-05-04
6 active 2013-09-09
6 inactive 2016-04-14
6 recruit 2016-06-22
6 active 2016-06-23
6 inactive 2017-04-30
In the case above, officer id 1 is active from 1st of May until the 4th of May.
This is essentially a 'housekeeping' task. The second row is not required and should be deleted. I would like to do this within a MySQL procedure that is linked an event on a schedule. I need a query that can identify these rows, but I'm not sure how.
In a previous system, I had looped through an ordered list and compared the current value against the previous row's value. I have read that loops in MySQL are not encouraged, so I'm trying to figure out how to do this with queries alone.
I tried the following:
SELECT
a.ActivityID, a.OfficerID, a.ChangeTo, a.ChangeDate
FROM
tbl_Officers_Activity as a
INNER JOIN tbl_Officers_Activity AS b
ON a.OfficerID = b.OfficerID
AND a.ChangeDate > b.ChangeDate
AND a.ChangeTo = b.ChangeTo
INNER JOIN tbl_Officers_Activity AS c
ON a.OfficerID = c.OfficerID
AND a.ChangeDate < c.ChangeDate
AND a.ChangeTo <> c.ChangeTo
ORDER BY
OfficerID,
ChangeDate;
I was hoping I could somehow embed the criteria I need into the joins, but I'm at a loss. any help would be greatly appreciated.
This is what you need
SQLFIddle Demo
select a1.officerid,a1.changedate,a1.changeto_a as changeto
From
(select a.officerid,a.changedate,max(a.changeto) as changeto_a,count(*) as rnk
from tbl_Officers_Activity a
inner join tbl_Officers_Activity b
on a.OfficerID=b.OfficerID
and a.ChangeDate>=b.ChangeDate
group by a.officerid,a.changedate) a1
left join
(select a.officerid,a.changedate,max(a.changeto) as changeto_b,count(*) +1 as rnk
from tbl_Officers_Activity a
inner join tbl_Officers_Activity b
on a.OfficerID=b.OfficerID
and a.ChangeDate>=b.ChangeDate
group by a.officerid,a.changedate) b1
on a1.officerid=b1.officerid
and a1.rnk=b1.rnk
where changeto_a = changeto_b
Explanation:
MySQL doesn't have row_Number function, so first I had to derive it. I used this query to get row_number, which is names as rnk in the query. Call the table a1.
(select a.officerid,a.changedate,max(a.changeto) as changeto_a,count(*) as rnk
from tbl_Officers_Activity a
inner join tbl_Officers_Activity b
on a.OfficerID=b.OfficerID
and a.ChangeDate>=b.ChangeDate
group by a.officerid,a.changedate)
Now as MySQL doesn't have LEAD function also, I derived it by using the above query again, and changing the rnk to rnk+1, calling it b1.
Now to replicate LEAD, I left joined a1 with b1
Now using a where clause to find same changeto, you can get your output.
My solution in the end was similar to what Utsav posted, however, after comparing his solution to mine, I found mine to be accurate, and his inaccurate.
For my solution, I create a temporary table for the initial ordered list with an auto incremental primary key. Then clone the temp table and join on itself with the primary pk equal to itself +1 and also equal to the status change.
my procedure ends up like this:
-- create temp table
DROP TABLE IF EXISTS tmp_act;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act (
AutoID INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
ActivityID INT(11),
OfficerID INT(11),
ChangeTo text
);
-- temp data
insert into tmp_act (ActivityID,OfficerID,ChangeTo)
SELECT
a.ActivityID, a.OfficerID, a.ChangeTo
FROM
tbl_Officers_Activity as a
ORDER BY
OfficerID,
ChangeDate;
-- housekeeping
DROP TABLE IF EXISTS tmp_act1;
DROP TABLE IF EXISTS tmp_act2;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act1 AS (SELECT * FROM tmp_act);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_act2 AS (SELECT * FROM tmp_act);
SELECT
a.AutoID, a.ActivityID, a.OfficerID, a.ChangeTo
FROM
tmp_act1 as a
INNER JOIN tmp_act2 AS b
ON a.OfficerID = b.OfficerID
AND a.ChangeTo = b.ChangeTo
AND a.AutoID = b.AutoID+1;

Inner query is difficult to write

I have two tables:
customer with schema_id
Schema table has: schema_id, period, amt, updated_date
I need to take join of customer and schema but only retrieve the latest record joined and not the others.
customer table
cust_id name schema_id
1 ABC 1
Schema table
schema_id period amt updated_date
1 1 100 2010-4-1
1 2 150 2011-4-1
If you need the max(updated_date) for each schema_id, then you can use an subquery:
select c.cust_id, c.name, c.schema_id, s.period, s.amt, s.updated_date
from customer c
inner join
(
select s1.schema_id, s1.period, s1.amt, s1.updated_date
from `schemas` s1
inner join
(
select schema_id, max(updated_date) MaxDate
from `schemas`
group by schema_id
) s2
on s1.schema_id = s2.schema_id
and s1.updated_date = s2.maxdate
) s
on c.schema_id = s.schema_id
See SQL Fiddle with Demo
The subquery is then used in a join back to your table to return the rows that have the matching date and schema_id.
If I understood your problem, you need to take lastest register of the "schema".
I think you need to use max() function. So, try the query below:
select *
from customer c,
schema s
where c.schema_id = s.schema_id
and s.updated_date = ( select max(s2.updated_date)
from schema s2
where s2.schema_id = s.schema_id
)
Regards!
Edmilton

How to left join or inner join a table itself

I have this data in a table, for instance,
id name parent parent_id
1 add self 100
2 manage null 100
3 add 10 200
4 manage null 200
5 add 20 300
6 manage null 300
How can I left join or inner join this table itself so I get this result below?
id name parent
2 manage self
4 manage 10
6 manage 20
As you can I that I just want to query the row with the keyword of 'manage' but I want the column parent's data in add's row as the as in manage's row in the result.
Is it possible?
EDIT:
the simplified version of my actual table - system,
system_id parent_id type function_name name main_parent make_accessible sort
31 30 left main Main NULL 0 1
32 31 left page_main_add Add self 0 1
33 31 left page_main_manage Manage NULL 0 2
my actual query and it is quite messy already...
SELECT
a.system_id,
a.main_parent,
b.name,
b.make_accessible,
b.sort
FROM system AS a
INNER JOIN -- self --
(
SELECT system_id, name, make_accessible, sort
FROM system AS s2
LEFT JOIN -- search --
(
SELECT system_id AS parent_id
FROM system AS s1
WHERE s1.function_name = 'page'
) AS s1
ON s1.parent_id = s2.parent_id
WHERE s2.parent_id = s1.parent_id
AND s2.system_id != s1.parent_id
ORDER BY s2.sort ASC
) b
ON b.system_id = a.parent_id
WHERE a.function_name LIKE '%manage%'
ORDER BY b.sort ASC
result I get currently,
system_id main_parent name make_accessible sort
33 NULL Main 0 1
but I am after this,
system_id main_parent name make_accessible sort
33 self Main 0 1
You just need to reference the table twice:
select t1.id, t1.name, t2.id, t2.name
from TableA t1
inner join TableA t2
on t1.parent_id = t2.Id
Replace inner with left join if you want to see roots in the list.
UPDATE:
I misread your question. It seems to me that you always have two rows, manage one and add one. To get to "Add" from manage:
select system.*, (select parent
from system s2
where s2.parent_id = system.parent_id
and s2.name = 'add')
AS parent
from system
where name = 'manage'
Or, you might split the table into two derived tables and join them by parent_id:
select *
from system
inner join
(
select * from system where name = 'add'
) s2
on system.parent_id = s2.parent_id
where system.name = 'manage'
This will allow you to use all the columns from s2.
Your data does not abide to a child-parent hierarchical structure. For example, your column parent holds the value 10, which is not the value of any id, so a child-parent association is not possible.
In other words, there's nothing that relates the record 2,manage,null to the record 1,add,self, or the record 4,manage,null to 3,add,10, as you intend to do in your query.
To represent hierarchical data, you usually need a table that has a foreign key referencing it's own primary key. So your column parent must reference the column id, then you can express a child-parent relationship between manage and add. Currently, that's not possible.
UPDATED: Joining by parent_id, try:
select m.id, m.name, a.parent
from myTable m
join myTable a on m.parent_id = a.parent_id and a.name = 'add'
where m.name = 'manage'
Change the inner join to a left join if there may not be a corresponding add row.