Trying to join two tables together, I want to filter the select results based on a parameter in the first table and the second table. Having an issue in the not exists where I only want either the value when no value exists, or the custdef_id is one of two values, 13 or 15. So Having the exist does not select the data where the value does not exist, so trying a not exist condition to filter all stated custdef_id values of 20 and 21 but then it also cuts off the 15 value?
First query:
SELECT
BILL_NUMBER,
deliver_by_end,
actual_delivery,
c.custdef_id,
(case when c.custdef_id = '13' then c.data end) "Late Flag",
(case when c.custdef_id = '15' then c.data end) "Planned Late Flag"
FROM TLORDER_all T LEFT join custom_data c on t.detail_line_id = c.src_table_key
WHERE
bill_number in ('T119633','T119634','T121374')
AND DATE(T.DELIVER_BY) between :STARTDATE and :ENDDATE
and companY_id = '1'
AND T.ACTUAL_DELIVERY IS NOT NULL
AND ((T.ACTUAL_DELIVERY > (T.DELIVER_BY_END + :MINUTESLATE MINUTES) AND TIME(T.DELIVER_BY_END) <> '00:00:00') OR
((TIME(T.DELIVER_BY_END)) = '00:00:00' AND T.ACTUAL_DELIVERY >= T.DELIVER_BY_END + 1 DAY))
order by
customer, bill_number
query results:
BILL_NUMBER DELIVER_BY_END ACTUAL_DELIVERY CUSTDEF_ID Late Flag Planned Late Flag
T119633 1/31/2023 23:59:00 2/3/2023 9:22:03 <null> <null> <null>
T119634 1/31/2023 23:59:00 2/6/2023 11:57:17 <null> <null> <null>
T121374 1/27/2023 1:30:00 1/27/2023 2:02:36 20 <null> <null>
T121374 1/27/2023 1:30:00 1/27/2023 2:02:36 21 <null> <null>
T121374 1/27/2023 1:30:00 1/27/2023 2:02:36 15 <null> Yes
I want the first two rows and last row. The repeating rows of 3 an 4 are pulling values I do not want. Tried a second query with a not exist of those CUSTDEF_ID of 20 and 21, and then I lose all but the first two rows?
SELECT
BILL_NUMBER,
deliver_by_end,
actual_delivery,
c.custdef_id,
(case when c.custdef_id = '13' then c.data end) "Late Flag",
(case when c.custdef_id = '15' then c.data end) "Planned Late Flag"
FROM TLORDER_all T LEFT join custom_data c on t.detail_line_id = c.src_table_key
WHERE
not EXISTS(SELECT * FROM CUSTOM_DATA C WHERE T.DETAIL_LINE_ID = C.SRC_TABLE_KEY and C.custdef_id NOT in ('20','21') )
and bill_number in ('T119633','T119634','T121374')
AND DATE(T.DELIVER_BY) between :STARTDATE and :ENDDATE
and companY_id = '1'
AND T.ACTUAL_DELIVERY IS NOT NULL
AND ((T.ACTUAL_DELIVERY > (T.DELIVER_BY_END + :MINUTESLATE MINUTES) AND TIME(T.DELIVER_BY_END) <> '00:00:00') OR
((TIME(T.DELIVER_BY_END)) = '00:00:00' AND T.ACTUAL_DELIVERY >= T.DELIVER_BY_END + 1 DAY))
order by
customer, bill_number
Results:
BILL_NUMBER DELIVER_BY_END ACTUAL_DELIVERY CUSTDEF_ID Late Flag Planned Late Flag
T119633 1/31/2023 23:59:00 2/3/2023 9:22:03 <null> <null> <null>
T119634 1/31/2023 23:59:00 2/6/2023 11:57:17 <null> <null> <null>
Using NOT IN inside a NOT EXISTS might be tripping you up, but it's hard to say exactly as we cannot see the DETAIL_LINE_ID value.
Why not simply use:
WHERE (CUSTDEF_ID IS NULL OR CUSTDEF_ID IN ('13','15'))
Related
I have two tables as follow:
position
--------------------------------
position_id description
17 team_lead
18 accountant
19 it_specialist
20 consultant
--------------------------------
assignment
------------------------------------------------------------
position_id people_id start stop
17 1001 2020-01-01 2021-06-01
17 1002 2021-06-01 2021-08-01
18 1003 2020-01-01 2021-12-01
19 1004 2020-01-01 2021-08-01
------------------------------------------------------------
I want to retrieve the positions that have no assignment today (2021-08-12), regardless if they had past assignments or not. The expected output should be:
position_id
17
19
20
How can I do this ? My attempts to use a left join like:
select
position.position_id
from position
left join assignment
on
assignment.position_id = position.position_id
where
/* incorrect. How to match a non-interval ? */
assignment.start >= DATE('now') or assignment.stop <= DATE('now')
fail to properly match what I want.
You can use not exists:
select p.*
from positions p
where not exists (select 1
from assignments a
where a.position_id = p.position_id and
a.start <= current_date and
a.stop >= current_date
);
It is not clear from your question is the stop date is included. That would affect the last comparison.
I am Having table like this:
id candid candname status date time location jobcode
1 12 hhhhhhhhhh Introduce 2014-05-21 14:0 NewYork 10JN
3 12 hhhhhhhhhh Reject 2014-05-21 15:0 AM London 10JN
4 12 hhhhhhhhhh Interview 2014-05-21 15:0 PM Chicago 10JN
5 11 Pinky Bare Introduce 2014-05-21 65:6 India 10JN
6 11 Pinky Bare Interview 2014-05-21 4:56 AM 10JN
7 13 chetan Tae Introduce 2014-05-21 4:54 AM Nagpur faOl
8 13 chetan Tae Interview 2014-05-21 3:45 Pune faOl
9 14 manisha mane Introduce 2014-05-21 3:33 PM Pune faOl
10 18 ranju gondane Introduce 2014-05-28 3:44 Nagpur AQW-06
12 18 ranju gondane Interview 2014-05-28 5:45 45454 AQW-06
13 18 ranju gondane Reject 2014-05-28 43:43 rsds AQW-06
14 19 vandanna rai Introduce 2014-05-28 7:7 yyyr AQW-06
if i use query
SELECT COUNT(*) FROM [tablename]
WHERE
(jobcode='AQW-06')
AND
([status] <> 'Interview' AND [status] <> 'Reject'
AND
[status] <> 'ON-Hold' AND [status] <> 'Hire')
I get count 2 for introduce candidates..
if the candidate is interviewd after introduce, it will not counted as Introduce
I want the count of Introduce, interviewd, rejected candidates of specofic jobcode
Please help me for this.
You can try
select status, count(*)
from [tablename]
where jobcode = 'AQW-06'
group by status
Edit: You can try use something like this
select count(x.candid) numofcandidates, x.statusnum
from
(select candid, max(case when status = 'Reject' then 3
when status = 'Interview' then 2
when status = 'Introduce' then 1 end) statusnum
from [tablename] t
where jobcode = 'AQW-06'
group by candid) x
group by x.statusnum;
What I actually did is to "translate" the status to a number, so I can use the highest status first. All you need to do then it to "translate" back the statusnum to the values of your table. In my opinion I would use a statusnum in my table directly
Try this:
;with reftable as
(select 1 'key', 'Introduce' 'val'
union
select 2 'key', 'Interview' 'val'
union
select 3 'key', 'Rejected' 'val'
),
cte as
(select e.candid, e.[status], row_number() over (partition by e.candid order by r.[key] desc) rn
from yourtable e
inner join reftable r on e.[status] = r.val
where e.[status] in ('Introduce','Interview','Rejected')
and e,jobcode = 'AQW-06')
select [status], count([status])
from cte
where rn = 1
group by [status]
Basically, we assign a numeric value to your text status to allow sorting. In the over clause, we sort by this numeric value in descending order to get the highest status of a candidate as you describe. Then, we just count the number of occurrences of each status.
Note that you can extend this to include values for status like 'Hire'. To do this, you will need to add it to the list in reftable with appropriate numeric value, and also add it to the filter in cte.
I want the count of Introduce, interviewed, rejected candidates of specific jobcode
The query below will return the results you need:
SELECT SUM(t.IsIntroduction) AS CountOfIntroductions,
SUM(t.IsInterview) AS CountOfInterviews,
SUM(t.IsRejected) AS CountOfRejections
FROM (
SELECT id,
CASE WHEN Status = 'Introduce' THEN 1 ELSE 0 END AS IsIntroduction,
CASE WHEN Status = 'Interview' THEN 1 ELSE 0 END AS IsInterview,
CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END AS IsRejected
FROM [Tablename]
WHERE JobCode = 'AQW-06'
) AS t
Sample at this SQL Fiddle.
My current sql:
select s.dcid, substr(s.lastfirst,0,3), to_char(a.att_date, 'mm/dd/yyyy'), a.periodid, p.name, a.attendance_codeid, ac.att_code, count(*)
from students s
join attendance a on s.id = a.studentid
join period p on a.periodid = p.id
join attendance_code ac on a.attendance_codeid = ac.id
WHERE ac.att_code IS NOT NULL
AND s.schoolid = 109
AND s.enroll_status = 0
AND s.student_number = 100887
AND a.att_date >= to_date('08/15/2013', 'mm/dd/yyyy')
group by s.dcid, s.lastfirst, to_char(a.att_date, 'mm/dd/yyyy'), a.periodid, p.name, a.attendance_codeid, ac.att_code
Output:
I would like to get the output to sequentially number each record where the count(*) column is, starting with 1 at each new group, and put a total at the bottom of the group, but I'm not sure how to do that. I have tried rollup at various parts of the group by expression, but it winds up giving subtotals for the dates, periodids, etc... I need it to total ONLY for the student (either s.dcid or s.lastfirst)
[Additional information per request...]
I'm hoping to achieve a report where my end users can search for students who have a given number of attendance records in a date range. For example, if the end user wants to find students who have 20 absences between 10/1/2013 and 10/31/2013, where the att_code is one of A,C,E,G... etc. Once the report runs, I want to show them the date the absence occurred, and the code that was used as a visual verification that the records found do indeed match their search criteria.
The output should look like the current output with the exception of the COUNT(*) column, which is where I'm hung up right now. I like how row_number sequentially numbers each record, but what I'm still seeking is how to reset the sequential numbering when the group (the student) changes.
For example...
DCID S.LASTFIRST A.ATT_DATE PERIODID NAME ATT_CODE COUNT(or # or Num...)
1006 Aco 08/29/2013 1704 4 W 1
1006 Aco 09/03/2013 1701 1 6 2
1006 Aco 09/05/2013 1706 6 G 3
...
1006 Aco 10/04/2013 1706 6 z 20
2543 Bro 08/29/2013 1704 4 W 1
2543 Bro 09/03/2013 1701 1 6 2
2543 Bro 09/05/2013 1706 6 G 3
...
2543 Bro 10/04/2013 1706 6 z 20
3121 Com 08/29/2013 1704 4 W 1
3121 Com 09/03/2013 1701 1 6 2
3121 Com 09/05/2013 1706 6 G 3
...
3121 Com 10/04/2013 1706 6 z 20
Of course, in this example, I am abbreviating the output by replacing row numbers 4 - 19 in each of the three groups with '...' I don't want to literally output this.
The ROW_NUMBER() analytical function will, unsurprisingly, number rows sequentially using the partitions and ordering you specify.
select s.dcid,
substr(s.lastfirst,0,3),
to_char(a.att_date, 'mm/dd/yyyy'),
a.periodid,
p.name,
a.attendance_codeid,
ac.att_code,
ROW_NUMBER() OVER ( ORDER BY s.dcid )
from students s
join attendance a on s.id = a.studentid
join period p on a.periodid = p.id
join attendance_code ac on a.attendance_codeid = ac.id
WHERE ac.att_code IS NOT NULL
AND s.schoolid = 109
AND s.enroll_status = 0
AND s.student_number = 100887
AND a.att_date >= to_date('08/15/2013', 'mm/dd/yyyy')
GROUP BY s.dcid,
s.lastfirst,
to_char(a.att_date, 'mm/dd/yyyy'),
a.periodid,
p.name,
a.attendance_codeid,
ac.att_code;
From your screenshot the COUNT() column is always 1 so the ROW_NUMBER() will also always be one (as that appears to be the maximum size of each group).
If this is not meant to be the case then you will need to be less restrictive in your GROUP BY clause - however you have not given enough information on what you expect the query to do for me to make any changes.
Use ROW_NUMBER function as follows:
SELECT s.dcid,
SUBSTR (s.lastfirst, 0, 3),
TO_CHAR (a.att_date, 'mm/dd/yyyy'),
a.periodid,
p.name,
a.attendance_codeid,
ac.att_code,
ROW_NUMBER() OVER (ORDER BY s.dcid) AS rownumber
-- I have ordered by s.dcid. You can order by whichever column you want.
FROM students s
JOIN attendance a ON s.id = a.studentid
JOIN period p ON a.periodid = p.id
JOIN attendance_code ac ON a.attendance_codeid = ac.id
WHERE ac.att_code IS NOT NULL
AND s.schoolid = 109
AND s.enroll_status = 0
AND s.student_number = 100887
AND a.att_date >= TO_DATE ('08/15/2013', 'mm/dd/yyyy');
rank function? can anybody assist me with this. I'd like my query to only return the lowest date for the P0260 field, and the lowest date for the painting field.
JOB ID LINE ORDER RCVD USE DATE
P0260 61785 1 2400 24 10/26/2012
P0260 63462 3 2400 24 11/14/2012
P0260 66372 1 1 0 2/15/2013
P0260 66371 1 5 0 3/1/2013
PAINTING 12246 1 29 27 11/30/2006
PAINTING 30885 1 160 0 9/29/2009
Painting 30885 2 160 0 9/29/2009
PAINTING 31155 1 25 0 11/6/2009
Ok, without knowing wich RDBMS (and version) you are using, this solution should work on most of them:
SELECT A.*
FROM YourTable A
INNER JOIN (SELECT JOB, MIN([USE DATE]) MinUseDate
FROM YourTable
GROUP BY JOB) B
ON A.JOB = B.JOB AND A.[USE DATE] = B.MinUseDate
SELECT query2.PART_ID, query2.ID, query2.LINE_NO, query2.DEL_SCHED_LINE_NO, query2.SYSADM_PURC_LINE_DEL.ORDER_QTY, query2.RECEIVED_QTY, query2.DESIRED_RECV_DATE, query2.SYSADM_PURC_ORDER_LINE.ORDER_QTY, query2.TOTAL_RECEIVED_QTY, query2.[USE DATE]
FROM query2
INNER JOIN (SELECT query2.PART_ID, MIN(query2.[USE DATE]) MinUseDate
FROM query2
GROUP BY PART_ID) B
ON query2.PART_ID = B.PART_ID AND query2.[USE DATE] = B.MinUseDate;
I wasn't sure what could be the title for my question so sorry about that.
I'm trying to write a SQL query to achieve the no. of members who should get reimbursed from a pharmacy.
For example : I went to pharmacy, I took a vaccine but by mistake I paid from my pocket. so now Pharmacy needs to reimburse me that amount. Lets say I have the data like:
MemberId Name ServiceDate PresNumber PersonId ClaimId AdminFee(in $)
1 John 1/1/2011 123 345 456 0
1 John 1/21/2011 123 345 987 20
2 Mike 2/3/2011 234 567 342 0
2 Mike 2/25/2011 234 567 564 30
5 Linda 1/4/2011 432 543 575 0
5 Linda 4/6/2011 987 543 890 0
6 Sonia 2/6/2011 656 095 439 0
This data shows all members from that pharmacy who got reimbursed and who haven't.
I need to find out the member having AdminFee 0 but i also need to check another record for the same member having same PresNumber, same PersonId where the ServiceDate falls within 30 Days of the Original Record.
If another record meets this criteria and the AdminFee field contains a value (is NOT 0) then it means that person has already been reimbursed. So from the data you can see John and Mike have already been reimbursed and Linda and Sonia need to be reimbursed.
Can anybody help me how to write an SQL query on this?
You don't mention what SQL engine you're using, so here is some generic SQL. You'll need to adapt the date math and the return of True/False ( in the second option) to whatever engine you're using:
-- Already reimbursed
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
-- Need reimbursement
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND NOT EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
or
-- Both in one.
SELECT YT1.*,
CASE WHEN YT2.MemberID IS NULL THEN False ELSE True END AS AlreadyReimbursed
FROM YourTable YT1 JOIN YourTable YT2 ON
YT1.MemberID = YT2.MemberID AND
YT1.PresNumber = YT2.PresNumber AND
YT1.ServiceDate <= YT2.ServiceDate + 30
WHERE YT1.AdminFee = 0 AND YT2.AdminFee > 0)
You need to use datediff function in SQL Server and as parameter to pass day and to join the table above by other alias. I do not have SQL Server but I think it should be like this
Select memberid
from PaymentLog p
inner join PaymentLog d on p.serviceid = d.serviceid
and p.memberid = d.memberid
and p.personid = d.personid
Where adminfee = 0
and datediff(day, p.servicedate, d.servicedate) < 30
I called a table paymentlog