How to display a non matching value also? - ms-access

USING VB6 AND MS-ACCESS 2003
So on…,
TABLE 1
EMPID DATE
101 22-07-2009
201 22-07-2009
501 22-07-2009
301 23-07-2009
401 23-07-2009
501 23-07-2009
101 24-07-2009
501 24-07-2009
So on…,
From the above table two tables I want to display all EMP ids for the date wise
Expected Output
EMPID DATE
101 22-07-2009
201 22-07-2009
301
401
501 22-07-2009
101
201
301 23-07-2009
401 23-07-2009
501 23-07-2009
101 24-07-2009
201
301
401
501 24-07-2009
So on…,
Need Query Help.

Haven't executed to verify for sure, but this should get you most of the way there:
SELECT
AllPossibleCardEvents.PersonId,
AllPossibleCardEvents.EmpName,
AllPossibleCardEvents.TitleCode,
AllPossibleCardEvents.TitleName,
AllPossibleCardEvents.CardEventDate,
ActualCardEvents.CardEventDate AS MatchingCardEventDate
FROM
(
(
SELECT
p.PersonId,
p.EmpName,
p.TitleCode,
p.TitleName,
AllDates.CardEventDate
FROM
(SELECT DISTINCT CardEventDate FROM T_Cardevent) AllDates,
T_Person p
) AllPossibleCardEvents
LEFT OUTER JOIN T_Cardevent ActualCardEvents ON
AllPossibleCardEvents.PersonId = Actual.PersonId AND
AllPossibleCardEvents.CardEventDate = Actual.CardEventDate
)
Where "MatchingCardEventDate" will be NULL for records that are NOT actual events. For actual events, the value of "MatchingCardEventDate" will be the valid date.
Hope this helps.

Without questioning your data model, to get the results you want you will need a third table (which I will call Dates) You need a Cross Join on Table 1 and Dates, which will give a result of all employees for all days. Then you need to Left Join to EmpID and Date.
The Left Join will include all of the results from the first join but only the matching rows from Table 2 will be populated. Access is funny in how it handles query structure, also it does not support the SQL-92 CROSS JOIN syntax, but it would look something like the below.
SELECT t1.EmpID, t2.Date
FROM (
SELECT t1.EmpID, d.Date
FROM [Table 1] AS t1,
Dates AS d
) AS DT1
LEFT OUTER JOIN [Table 2] AS t2
ON DT1.EmpID = t2.EmpID
AND DT1.Date = t2.Date
ORDER
BY DT1.Date, DT1.EmpID;

Related

Join two tables using mysql

table:tab1
id date_time zoneid accountid slotid trequest bidder width height
_50832 2017-09-04 15:41:06 153 1654 153x468x60 10 aaa 468 60
_50832 2017-09-04 15:41:06 152 1654 152x468x60 10 bbb 468 60
table:tab2
id date_time zoneid accountid slotid bidder count
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 6
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 4
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 9
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 1
below is my query:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN tab2 as win ON (req.id=win.id AND req.zoneid=win.zoneid)
GROUP BY req.zoneid
I get below result,
REQ IMP
20 10
20 10
IMP count is correct but I get wrong REQ count. My expected result is
REQ IMP
10 10
10 10
How to get my expected result?
Lets find the sum of trequest and count separately based on zoneid and id.Then use these two results ( t1 and t2 ) in the inner join.
Count mismatch problem shown in the question occur due to multiple rows satisfying the joining conditions.
In this solution we will only have one entry for each zoneid in both the results ( t1 and t2 ). So the problem is avoided.
Note: You can remove the id column from the GROUP BY clause if it doesn't make any difference.
SELECT t1.id, t1.zoneid, t1.REQ, t2.IMP FROM
(SELECT id,zoneid,SUM(trequest) as REQ
FROM tab1 GROUP BY zoneid,id ) t1
INNER JOIN
(SELECT id,zoneid SUM(win.count) as IMP
FROM tab2 GROUP BY zoneid,id ) t2
ON t1.id = t2.id
AND t1.zoneid = t2.zoneid
Let's try first sumwin.count and group records in sub-query, after it join tables. Try in following:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN (
SELECT SUM(win.count) as IMP, win.zoneid, win.id
FROM tab2 as win
GROUP BY win.zoneid, win.id) AS win ON req.id=win.id AND req.zoneid=win.zoneid
GROUP BY req.zoneid
Instead of req.zoneid. You should try win.zoneid. What seems is that the rows in table 1 are counted multiple times as zoneid in table 2 comes twice. So win.zoneid would group it and avoid the repetition.
Updated: The solution posted by #mayur panchal is the correct one as you don't need to SUM the rows in first table as they belong to different zoneid. If you SUM them you will obviously get the 20 repeated twice.

how to avoid duplicate data in sql command

I try to use DISTINCT to avoid duplication of the data, but no work.
How to avoid the duplicate data?
Table 1
Employee code Deduction Voucher no Dec_Amount
001 999 50
001 888 20
002 777 100
Table 2
Employee code Payslip Voucher No Pay_Amount
001 111 100
002 222 200
The output should be:
Employee code Deduction Voucher no Dec_Amount Payslip Voucher No Pay_Amount
001 999 50 111 100
001 888 20
002 777 100 222 200
But i got the table like this.
Employee code Deduction Voucher no Dec_Amount Payslip Voucher No Pay_Amount
001 999 50 111 100
001 888 20 111 100
002 777 100 222 200
You cannot get those results with just a SQL query. It seems to me you need it in this format for display in a table/excel spreadsheet. If this is the case you would have to handle the "Hiding" of the particular entries with some other code. The reason is because the entries you want to hide are correctly associated with the 001 employee.
While I do agree this probably makes a lot more sense to do in your front end code, it is possible to do in SQL. Using a variable you get a function similar to SQL Server's ROW_NUMBER function and then only join on the first row per employee code.
See the sqlfiddle - http://sqlfiddle.com/#!2/47302/11
SELECT t1.`Employee code`,`Deduction Voucher no`,`Dec_Amount`,
COALESCE(`Payslip Voucher No`,'') as `Payslip Voucher No`,
COALESCE(CAST(`Pay_Amount` as char(10)),'') as `Pay_Amount`
FROM Table2 t2
RIGHT JOIN
(
SELECT #row_num := IF(#prev_value=`Employee code`,#row_num+1,1) AS RowNumber
,`Employee code`,`Deduction Voucher no`,`Dec_Amount`
,#prev_value := `Employee code`
FROM Table1,
(SELECT #row_num := 1) x,
(SELECT #prev_value := '') y
ORDER BY `Employee code`
) t1
ON t1.`Employee code`=t2.`Employee code` AND t1.RowNumber=1
To expand on #d.lanza38's answer, there is no way given for the DB to tell which row in table1 should get the data from table2. Remember that there is no order to the data in the database, so there is no inherent concept of "the first row with employee code 001".
A standard (inner) join will put them as you have shown - on both. Which is actually correct - your table structures say that for every payslip in table2, there can be many deductions. So if you want the data from both tables, the deductions have to have the matching payslip data attached.
You can't use DISTINCT to magically fix your data - you need to understand the data structures, and relate them correctly.
To get what is in your example (which may be wrong) try this SQL:
select
a.Employee_code,
Deduction_Voucher_no,
Dec_Amount,
Payslip_Voucher_No,
Pay_Amount
from
table1 as a
inner join table2 as b on a.employee_code = b.employee_code
where Deduction_Voucher_no = (
select max(Deduction_Voucher_no)
from table1 as c
where a.Employee_code = c.Employee_code)
UNION
select
a2.Employee_code,
Deduction_Voucher_no,
Dec_Amount,
null as Payslip_Voucher_No,
null as Pay_Amount
from
table1 as a2
inner join table2 as b2 on a2.employee_code = b2.employee_code
where Deduction_Voucher_no <> (
select max(Deduction_Voucher_no)
from table1 as c2
where a2.Employee_code = c2.Employee_code)
order by 1,2 desc
Note: untested, because I don't have your database, and don't even know which database engine you are using. If it complains about selecting nulls, replace with 0 or '' depending upon the data type.
UPDATE improved SQL and provided a fiddle: http://sqlfiddle.com/#!2/e7fc2/2

Mysql join with one to many relations

claims
c_id claim id
1 201
2 202
3 203
4 204
claim_status
cs_id claim_id status
1 201 created
2 202 created
3 202 submitted
4 203 submitted
5 204 created
If the claim is created and submitted(like claim_id 202) it would not show up if i search with 'created' condition. this is my main requirement. i need result like below
If i search with status='created' i need to get records as below
c_id claim_id cs_id claim_id status
1 201 1 201 created
4 204 5 204 created
If i search with status='submitted' i need to get records as below
c_id claim_id cs_id claim_id status
2 202 3 202 submitted
3 203 4 203 submitted
But i'm unable to achive my result with below query. I'm new to stackoverflow. so please forgive me if i'm wrong in clear posting.
SQL:
SELECT * from claims c
INNER JOIN claim_status cs
ON c.claim_id = cs.claim_id
WHERE cs.status='created'
GROUP BY cs.claim_id
for 'created':
SELECT * from claims c
INNER JOIN claim_status cs
ON c.claim_id = cs.claim_id
WHERE cs.status='created'
for 'submitted':
SELECT * from claims c
INNER JOIN claim_status cs
ON c.claim_id = cs.claim_id
WHERE cs.status='submitted'
To get claims that are created but not submitted try this:
SELECT * from claims c
INNER JOIN claim_status cs
ON c.claim_id = cs.claim_id
WHERE cs.status='created'
AND NOT EXISTS (
SELECT 1
FROM claim_status cs2
WHERE cs2.claim_id = cs.claim_id
AND cs2.status='submitted'
)
Are those your actual tables? why are you handling claim statuses on another table than claims? You should have a "status" column on "claims" and you are done. You could have another table for versioning (if you want to get older states of the claim) and save changes, timestamps, etc, but for the current status is much better to have that on the same table
I know it's not the answer you are asking, but I think it's better to have something like:
SELECT * FROM claims WHERE status = 'created'
or
SELECT * FROM claims WHERE status = 'submitted'
It's faster, cleaner, better, everything (?)
Also, to make them even faster, status should be an integer column and "created" should have an associated number so you can do
SELECT * FROM claims WHERE status = <value that means created>
the same for submitted or any extra status

mySQL Query - select join if latest record in join table contains a specific value

I am trying to write a select statement with a right join (to clients), that will find a specific value in the join table - but ONLY if that is the most recent value for each client (ignoring blanks and nulls).
Clients
Id Name
0 John Doe
1 Frank Smith
2 Sue Smith
3 John Smith
Activity (join table)
ClientId Type Date
0 500 2013-01-01 00:00:08
1 900 2013-01-01 00:00:07
2 NULL 2013-01-01 00:00:06
3 2013-01-01 00:00:05
4 500 2013-01-01 00:00:05
0 800 2013-01-01 00:00:04
1 500 2013-01-01 00:00:03
2 500 2013-01-01 00:00:02
3 500 2013-01-01 00:00:01
4 800 2013-01-01 00:00:00
So this query will at least give me only the client records that have an activity type of 500 (in this case I would get back client 0 and 4):
select * from clients right join activity on activity.clientid = clients.id
where activity.type = 500
HOWEVER, I need to figure out how to make this return ONLY the first record in the above list of records. The logic there is Client #0 is the only client that has 500 as it's latest activity type = 500. The other 3 clients have NULL, blank, or 900 for example as their 'latest' activity type.
I am thinking some magic with ordering (the date would normally be pretty accurate), a 'top' and/or 'limit' and possibly union? Just cant quite wrap my head around it.
Please try this
SELECT activity.id AS activityid
, activity.type
, activity.date
, clients.id AS clientid
, clients.name
FROM activity
LEFT JOIN activity AS other_activities
ON activity.ClientID = other_activities.ClientID
AND activity.date < other_activities.date
LEFT JOIN clients
ON activity.ClientID = clients.id
WHERE activity.type = 500
AND other_activities.ClientID IS NULL;
SELECT * from Activity
INNER JOIN (SELECT MIN(Date) as min_date, clientID
FROM Activity
GROUP BY clientID) temp
ON Activity.clientID = temp.clientID
WHERE date = min_date and type = 500
This will return all clientID's whose most recent activity was of type 500.
This will get you the most recent Activity of type 500 and the client of that activity
SELECT * FROM
(SELECT *
FROM activity
WHERE type=500
ORDER BY date DESC
LIMIT 1) a
LEFT JOIN
clients c
ON (a.clientid = c.id)
of if you only want the result if it's the most recent activity and the type is 500 you can use
SELECT * FROM
(SELECT *
FROM activity
ORDER BY date DESC
LIMIT 1) a
LEFT JOIN
clients c
ON (a.clientid = c.id)
WHERE a.type = 500;
sqlFiddle here to get clients who have the latest activity of type 500
SELECT a1.ClientID,c.name,a1.Type,a1.Date
FROM activity a1
LEFT JOIN clients c ON (c.id = a1.clientid)
WHERE NOT EXISTS (SELECT 1
FROM activity a
WHERE a.clientid = a1.clientid
and a.date > a1.date)
AND a1.type = 500;

Join only first matching record from joining table without duplicate

I have two tables, 1. (inbox) keep delivery reports, 2. (outbox) keep send SMS. I can't add foreign key, and change datebase structure.
inbox
id number smsdate
-- ---------- -------------------
1 600600600 2013-08-16 11:51:18
2 700600600 2013-08-16 11:51:16
3 600600600 2013-08-16 11:51:14
4 900600600 2013-08-16 11:51:12
outbox
id number processed_date
--- ---------- -------------------
167 600600600 2013-08-16 10:51:10
288 700600600 2013-08-16 09:51:10
356 600600600 2013-08-16 08:51:10
473 900600600 2013-08-16 07:51:10
536 600600600 2013-08-16 06:51:10
I would now join the report of sent messages. I can do it in such a way that comparing the number and date of dispatch of the table outbox, with the same number and the nearest date of receipt of the table inbox. I am sure that the reports will be in order.
If i use
SELECT outbox.id, inbox.id, outbox.number, inbox.number,
outbox.processed_date, inbox.smsdate FROM outbox
LEFT JOIN inbox ON inbox.number= outbox.number
AND inbox.smsdate >= outbox.processed_date
GROUP BY outbox.id
ORDER BY outbox.id DESC;
I'm getting strange results and reports are duplicated. For if I have 3 sent, and 2 received, for the same number, it should be one empty. And instead of a blank for the latter, it duplicates my previous one.
I tried to add.
GROUP BY outbox.id, inbox.id
But it was even worse.
It is a way to solve this?
Desired output:
output
outbox.id inbox.id
--------- ----------
167 NULL
288 2
356 1
473 4
536 3
My approach is to use a correlated subquery to get the inbox id, and then join back to the inbox table to pull the columns you want:
select o.id, iid, o.number, i.number, o.processed_date, i.smsdate
from (select o.*,
(select i.id
from inbox i
where i.number = o.number and
i.smsdate >= o.processed_date
order by i.sms.date
limit 1
) iid
from outbox o
) o left outer join
inbox i
on o.iid = i.id
ORDER BY outbox.id DESC;
Try this::
SELECT outbox.id, inbox.id, outbox.number, inbox.number,
outbox.processed_date, inbox.smsdate FROM outbox
LEFT JOIN inbox ON inbox.number= outbox.number
WHERE inbox.smsdate >= outbox.processed_date