How to write select statement with if statement in where coundition - sql

I would like to write one select statement in postgres how could I place if condition in where condition
To creating a report in that suppose we have 20 country in our table and and we have three type of employee which having contact, payroll and permanent these are the employee_category I would like to get all employee details except India and USA who having contact employee in these two country if employee having payroll and permanent should come in result
something like this
SELECT
r.employee_id AS E_ID,
r.Joining_date AS J_DATE,
r.employee_type AS E_TYPE,
'NIL'::text AS REMARKS,
i.source as SOURCE,
i.user_orgname as USER_ORGNAME
from master_employee r
INNER JOIN users_master AS i ON r.user_id = i.loginid and i.userstatus = 'Active'
WHERE
if(country="india","USA"){
employee_category!='contract'
}
and
date(r.createddate) = date(now())
ORDER BY r.createddate ASC ;

Using the case statement should work.
SELECT
r.employee_id AS E_ID,
r.Joining_date AS J_DATE,
r.employee_type AS E_TYPE,
'NIL'::text AS REMARKS,
i.source as SOURCE,
i.user_orgname as USER_ORGNAME
from master_employee r
INNER JOIN users_master AS i ON r.user_id = i.loginid and i.userstatus = 'Active'
WHERE employee_category <> case when country in ("india","USA") then 'contract' end
and date(r.createddate) = date(now())
ORDER BY r.createddate ASC ;

Instead, use basic boolean logic:
where (country not in ('india', 'USA') or
employee_category <> 'contract'
) and
date(r.createddate) = date(now())

Related

Oracle SQL MAX and GROUP BY Costs too Much Lines of Code

I have this long query, where I want to fetch some data about employees:
SELECT e.id,
e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY') "GREGORIAN",
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah''') HIJRI,
ba.acc_number "Account Number"
to_char(c.id) "National ID",
en.name
FROM
relationships r,
rel_actions ra,
actions a,
payrolls p,
emp_names en,
citizenships c,
pay_methods pm,
bank_accounts ba,
assignments as,
emp e
WHERE r.id = ra.id
AND r.id=pm.id
AND as.id = e.id
AND r.id = e.id
AND en.id = e.id
AND en.NAME_TYPE ='GLOBAL'
AND a.action_type = 'T'
AND a.id = ra.id
AND a.id = p.id
and c.id = e.id
and ba.id=pm.id
AND a.effective_date BETWEEN ba.start_date AND ba.end_date
AND a.effective_date BETWEEN p.effective_start_date AND p.effective_end_date
AND a.effective_date BETWEEN r.start_date AND r.end_date
AND a.effective_date BETWEEN en.effective_start_date AND en.effective_end_date
AND a.effective_date BETWEEN e.effective_start_date AND e.effective_end_date
AND a.effective_date BETWEEN pm.effective_start_date AND pm.effective_end_date
AND a.effective_date BETWEEN as.effective_start_date AND as.effective_end_date
AND as.assignment_type = 'E'
AND SYSDATE BETWEEN as.effective_start_date AND as.effective_end_date
ORDER BY e.emp_number
the result of this query will be something like this :
emp_number account_number name national_id gregorian hijri
1 6456 john ^*&$^**$^** 6/12/2022 12/5/1444
1 6456 john ^*&$^**$^** 6/12/2022 12/5/1444
2 4121 Mathew %&#%^%&%&%^ 6/12/2022 12/5/1444
2 4121 Mathew %&#%^%&%&%^ 6/12/2022 12/5/1444
taking the first 2 rows for example, they have different effective_date, so I want to fetch the row that have the newest effective_date:
and a.effective_date in (
select effective_Date from pay_payroll_actions
where a.effective_date BETWEEN ba.start_date AND ba.end_date
AND a.effective_date BETWEEN p.effective_start_date AND p.effective_end_date
AND a.effective_date BETWEEN r.start_date AND r.end_date
AND a.effective_date BETWEEN en.effective_start_date AND en.effective_end_date
AND a.effective_date BETWEEN e.effective_start_date AND e.effective_end_date
AND a.effective_date BETWEEN pm.effective_start_date AND pm.effective_end_date
AND a.action_type = 'T'
AND a.id = ra.id
AND a.id = p.id
)
GROUP BY e.id, e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY'),
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah'''),
ba.acc_number ,
to_char(c.id),
en.name
my question is, do I really need to apply all related conditions in the sub-query in order to get the same effective dates resulted from the main query?
and if yes, its too long, is there a way to shorten this? thanks in advance
You can filter the duplicate rows using row_number ()
WITH cte
AS
(SELECT e.id,
e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY') "GREGORIAN",
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah''') HIJRI,
ba.acc_number "Account Number"
to_char(c.id) "National ID",
en.name,
row_number() over (partition BY e.id,
e.emp_number,ba.acc_number,c.id,en.name ORDER BY a.effective_date desc) AS dup_count
FROM your_query)
SELECT * FROM cte WHERE dup_count = 1;
OR Since you are already checking the dates between condition in your main query ,you can refine your sub query to
and a.effective_date in (
select effective_Date from pay_payroll_actions py
where a.id=py.id
)

Combine two queries to get the data in two columns

SELECT
tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity'
FROM
tblData
INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode
INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
WHERE
IsPSR = 'Y'
GROUP BY
tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,
tblEmployeeMaster.TeamName
ORDER BY
tblPhotos.TeamSort DESC, TotalQuantity DESC
This returns
Using this statement
select TeamName, count(TeamName) AS 'Head Count'
from dbo.tblEmployeeMaster
where IsPSR = 'Y'
group by teamname
Which returns
I would like to combine these 2 queries in 1 to get the below result.
Tried union / union all but no success :(
Any help will be very much helpful.
You can simply use the sub-query as follows:
SELECT tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity',
MAX(HEAD_COUNT) AS HEAD_COUNT, -- USE THIS VALUE FROM SUB-QUERY
CASE WHEN MAX(HEAD_COUNT) <> 0
THEN SUM(tblData.Quantity)/MAX(HEAD_COUNT)
END AS PER_MAN_CONTRIBUTION -- column asked in comment
FROM tblData INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
-- FOLLOWING SUB-QUERY CAN BE USED
LEFT JOIN (select TeamName, count(TeamName) AS HEAD_COUNT
from dbo.tblEmployeeMaster
where IsPSR = 'Y' group by teamname) AS HC
ON HC.TeamName = tblEmployeeMaster.TeamName
where IsPSR = 'Y'
GROUP BY tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,tblEmployeeMaster.TeamName
order by tblPhotos.TeamSort desc, TotalQuantity desc

How do I find the SUM of the following rows in SQL?

I have the following query in SQL :
SELECT LOCATION_CODE AS "Location",
AUTHORIZATION_STATUS AS "Authorization Status",
COUNT(authorization_status) AS "Requisition Lines Count",
imcb.SEGMENT1 AS "CATEGORY"
FROM apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla
ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb
ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P
ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl
ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu
ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
/* AND AUTHORIZATION_STATUS = 'APPROVED' */
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code ASC
And it yields the following output :
However, I would like it to have the total Count for a single location, regardless of Authorization Status. So , it should look like so :
Liberty Lake 826
Rather than
Liberty Lake 767
Liberty Lake 29
Liberty Lake 29
etc
How do I generate this result? I tried adding in a SUM like so:
sum(authorization_status),
but this gives me the following error:
ORA-01722: invalid number
Use a group by rollup instead of just group by
You'll get the current summaaries you have now plus rolled up summaries:
GROUP BY imcb.SEGMENT1, LOCATION_CODE, ROLLUP (authorization_status)
If you don't want any of the more detailed summaries, then remove authorization_status from both your select and group by lists.
You're trying to call the aggregate function SUM on a text field, which is why you are getting that error. SUM is for adding numeric values together. COUNT is used to count the occurrences of rows in that grouping scope. What I think you actually want to do is remove Authorization status from your query, so it would actually be:
SELECT LOCATION_CODE AS "Location",
COUNT(authorization_status) AS "Requisition Lines Count",
imcb.SEGMENT1 AS "CATEGORY"
FROM apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla
ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb
ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P
ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl
ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu
ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
/* AND AUTHORIZATION_STATUS = 'APPROVED' */
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY imcb.SEGMENT1 , LOCATION_CODE
ORDER BY Location_code ASC
Note that I removed it from both my SELECT list and my GROUP BY clause.

How to improve SQL query performance (correlated subqueries)?

I Would like to write the below query in a better & efficient way any help?
SELECT a.assetnum as Asset,
a.assettag as Asset_Tag,
a.manufacturer as Manufacturer,
a.serialnum as Serial,
a.description as Description,
(
SELECT CASE a.isrunning
WHEN 1
THEN 'Operational'
WHEN 0
THEN 'Down'
END
) AS Condition ,
l.kbs_loctag as Location,
(
SELECT TOP 1 wo.wonum
FROM workorder wo
WHERE wo.assetnum = a.assetnum
and wo.worktype = 'UN'
ORDER BY wo.reportdate DESC
) AS Last_Workorder,
(
SELECT wo.statusdate
FROM workorder wo
WHERE wo.wonum IN
(
SELECT top 1 wo.wonum
FROM workorder wo
WHERE wo.assetnum = a.assetnum
AND wo.worktype = 'UN'
ORDER BY wo.reportdate DESC
)
) AS Last_Status_Date,
(
SELECT top 1 lt.memo
FROM labtrans lt
WHERE lt.assetnum = a.assetnum
AND lt.transtype = 'REPAIR'
ORDER BY lt.transdate DESC
) AS Action
FROM asset a
LEFT OUTER JOIN locations l
ON a.location = l.location
WHERE (
a.description like '%WASH%'
or a.description LIKE '%DRYER%'
)
ORDER BY l.location,
a.description
In most cases I prefer to use APPLY operator instead of correlated subquery.
In your case I would suggest the next solution:
SELECT a.assetnum as Asset,
a.assettag as Asset_Tag,
a.manufacturer as Manufacturer,
a.serialnum as Serial,
a.description as Description,
CASE a.isrunning
WHEN 1 THEN 'Operational'
WHEN 0 THEN 'Down'
END AS Condition,
l.kbs_loctag as Location,
wo.wonum AS Last_Workorder,
wo.statusdate AS Last_Status_Date,
lt.memo AS Action
FROM asset a
LEFT OUTER JOIN locations l ON a.location = l.location
OUTER APPLY (
SELECT TOP 1 wonum, statusdate
FROM workorder
WHERE assetnum = a.assetnum
and worktype = 'UN'
ORDER BY reportdate DESC) AS wo
OUTER APPLY (
SELECT top 1 memo
FROM labtrans
WHERE assetnum = a.assetnum
AND transtype = 'REPAIR'
ORDER BY transdate DESC) AS lt
WHERE (
a.description like '%WASH%'
or a.description LIKE '%DRYER%'
)
ORDER BY l.location, a.[description]
BTW - you can find amazing video lesson (from Itzik Ben-Gan)about using APPLY Operator here.

Select all data not in Top 'n' as 'Other'

I hope somebody may be able to point out where i'm going wrong here but i've been looking at this for the last 30 minutes and not gotten anywhere with it.
I have a temporary table that is populated with data, the front end application cannot do any logic for me so please excuse the ugly case statement logic in the table.
The user is happy with the resultset brought back as I get the top 10 records. They have now decided they want to see a group of the remaining countries (all rows not in the top 10) as 'Other'.
I have tried to create a grouping of countries not in the top 10 but it's not working, I was planning on UNION'ing this result to the top 10 results.
SELECT c.Country, count(*) AS 'Total_Number_of_customers', COALESCE(ili.new_customers,0) AS 'New_Customers', COALESCE(ilb.existing_first,0) AS 'Existing_First_Trans', COALESCE(ilc.existing_old,0) AS 'Existing_Prev_Trans'
FROM #customer_tmp c
LEFT JOIN (SELECT z.country, count(*) AS 'new_customers' FROM #customer_tmp z where z.customer_type='New_Customer' group by z.country)ili ON ili.country = c.country
LEFT JOIN (SELECT zy.country, count(*) AS 'existing_first' FROM #customer_tmp zy where zy.customer_type='Existing_Customer' AND zy.first_transaction=1 group by zy.country)ilb ON ilb.country = c.country
LEFT JOIN (SELECT zx.country, count(*) AS 'existing_old' FROM #customer_tmp zx where zx.customer_type='Existing_Customer' AND zx.first_transaction=0 group by zx.country)ilc ON ilc.country = c.country
GROUP BY c.country, ili.new_customers, ilb.existing_first, ilc.existing_old
ORDER BY 2 DESC
Here is the SQL that I use to get results from my table.
For reference, each row in my temporary table contains a customer ID, the date they were created and their customer type, which is specific to what i'm trying to achieve.
Hopefully this is a simple problem and i'm just being a bit slow..
Many thanks in Adv.
Use the EXCEPT operator in SQL Server:
SELECT <fields>
FROM <table>
WHERE <conditons>
EXCEPT
<Query you want excluded>
Yup; EXCEPT, or maybe add a row number to your query and then select by that:
SELECT * FROM (
SELECT c.Country, count(*) AS 'Total_Number_of_customers',
row_number() OVER (ORDER BY COUNT(*) DESC) AS 'r',
COALESCE(ili.new_customers,0) AS 'New_Customers', COALESCE(ilb.existing_first,0) AS 'Existing_First_Trans', COALESCE(ilc.existing_old,0) AS 'Existing_Prev_Trans'
FROM #customer_tmp c
LEFT JOIN (SELECT z.country, count(*) AS 'new_customers' FROM #customer_tmp z where z.customer_type='New_Customer' group by z.country)ili ON ili.country = c.country
LEFT JOIN (SELECT zy.country, count(*) AS 'existing_first' FROM #customer_tmp zy where zy.customer_type='Existing_Customer' AND zy.first_transaction=1 group by zy.country)ilb ON ilb.country = c.country
LEFT JOIN (SELECT zx.country, count(*) AS 'existing_old' FROM #customer_tmp zx where zx.customer_type='Existing_Customer' AND zx.first_transaction=0 group by zx.country)ilc ON ilc.country = c.country
GROUP BY c.country, ili.new_customers, ilb.existing_first, ilc.existing_old
ORDER BY 2 DESC
) sub_query WHERE sub_query.r >= 10
This may be more flexible, as you can run one query and then divide the results up into "top ten" and "the rest" quite easily.
(This is equivalent to bobs' answer; I guess we were working on this at exactly the same time!)
Here's an approach using common table expressions (CTE)
WITH CTE AS
(
SELECT c.Country, count(*) AS 'Total_Number_of_customers', COALESCE(ili.new_customers,0) AS 'New_Customers', COALESCE(ilb.existing_first,0) AS 'Existing_First_Trans', COALESCE(ilc.existing_old,0) AS 'Existing_Prev_Trans'
, ROW_NUMBER() OVER (ORDER BY count(*) DESC) AS sequence
FROM #customer_tmp c
LEFT JOIN (SELECT z.country, count(*) AS 'new_customers' FROM #customer_tmp z where z.customer_type='New_Customer' group by z.country)ili ON ili.country = c.country
LEFT JOIN (SELECT zy.country, count(*) AS 'existing_first' FROM #customer_tmp zy where zy.customer_type='Existing_Customer' AND zy.first_transaction=1 group by zy.country)ilb ON ilb.country = c.country
LEFT JOIN (SELECT zx.country, count(*) AS 'existing_old' FROM #customer_tmp zx where zx.customer_type='Existing_Customer' AND zx.first_transaction=0 group by zx.country)ilc ON ilc.country = c.country
GROUP BY c.country, ili.new_customers, ilb.existing_first, ilc.existing_old
)
SELECT *
FROM CTE
WHERE sequence > 10
ORDER BY sequence
SELECT country, COUNT(*) cnt, SUM(new_customer), SUM(existing_first_trans), SUM(existing_prev_trans)
FROM (
SELECT CASE
WHEN country IN
(
SELECT TOP 10 country
FROM #customer_tmp
ORDER BY
COUNT(*) DESC
) THEN
country
ELSE 'Others'
END AS country,
CASE WHEN customer_type = 'New_Customer' THEN 1 END AS new_customer,
CASE WHEN customer_type = 'Existing_Customer' AND first_transaction = 1 THEN 1 AS existing_first_trans,
CASE WHEN customer_type = 'Existing_Customer' AND first_transaction = 0 THEN 1 AS existing_prev_trans,
FROM #customer_tmp
)
GROUP BY
country
ORDER BY
CASE country WHEN 'Others' THEN 2 ELSE 1 END, cnt DESC