How to write a Query to show multiple output in same column - sql

I have 2 tables tbl_emp & tbl_EmpSal where Emp_Id is primary_key in tbl_emp and foreign key for tbl_EmpSal as shown below.
create table tbl_emp
( Emp_Id int,
Emp_Name Varchar(20)
)
insert into tbl_emp(Emp_Id,Emp_Name)
select 1,'aaa'
union
select 2,'bbb'
union
select 3,'ccc'
union
select 4,'ddd'
--select * from tbl_emp
create table tbl_EmpSal
(Emp_id int,
EmpSal int)
insert into tbl_EmpSal
select 1,2000
union
select 2,4000
union
select 3,NULL
--select * from tbl_EmpSal
Now I want to write the SQL query to show output as below:
EMP_Name EmpSal/Details
aaa 2000
bbb 4000
ccc NEW JOINEE
ddd Contractor
The output shows that for any given Emp_id in tbl_EmpSal table if EmpSal column is NULL we have to show output as 'NEW JOINEE' in EmpSal/Details column.
And when there is no Row for any given Emp_id in tbl_EmpSal table we have to show output as 'Contractor' in EmpSal/Details column.

SELECT e.Emp_Name,
[EmpSal/Details] = CASE
WHEN s.EmpSal > 0 THEN CONVERT(VARCHAR(12), s.EmpSal)
WHEN s.Emp_id IS NOT NULL THEN 'NEW JOINEE'
WHEN s.EmpSal IS NULL THEN 'Contractor'
END
FROM dbo.tbl_emp AS e
LEFT OUTER JOIN dbo.tbl_EmpSal AS s
ON e.Emp_id = s.Emp_id;

This is a rather tricky question. It involves both a left outer join and distinguishing between a NULL value that is found and a missing match:
select Emp_Name,
(case when es.Emp_Id is NULL then 'Contractor'
when es.EmpSal is NULL then 'NEW JOINEE'
else cast(EmpSal as varchar(255))
end) as EmpSal_Details
from tbl_emp e left outer join
tbl_EmpSal es
on e.Emp_id = es.Emp_Id;

Related

Oracle 18c - Left join conditional USING clause

I have a cursor with a left join like so:
CURSOR c_emp
SELECT * FROM FROM EMP_NEW
LEFT JOIN
(SELECT EMP_ID,
DEPT_ID,
SUB_DEPT_ID,
EMP_UID,
FROM EMP)
USING (DEPT_ID, SUB_DEPT_ID, EMP_UID);
Which is then referenced in a for loop:
For i in c_emp
IF i.emp_id IS NULL
then
insert into emp...
else
update emp...
where emp_id = i.emp_id;
end if;
We have a scenario when loading new data into EMP table from the EMP_NEW table, the emp_new.dept_id and emp_new.emp_uid can have a duplicate in the EMP table with a different sub_dept_id value. When we get such new data, the emp.emp_id is not selected in the cursor, thus logic goes to INSERT instead of UPDATE. I would like for the duplicate emp_id to be selected so it goes to the UPDATE.
EMP data:
EMP_ID DEPT_ID SUB_DEPT_ID EMP_UID
123 1 10 123.123
EMP_NEW data:
DEPT_ID SUB_DEPT_ID EMP_UID
1 20 123.123
The above cursor currently returns the following:
EMP_ID DEPT_ID SUB_DEPT_ID EMP_UID
null 1 20 123.123
What I would like it to return:
EMP_ID DEPT_ID SUB_DEPT_ID EMP_UID
123 1 20 123.123
You seem to want to match on the 3 columns first and if not on just two columns. I think a lateral join better fits your needs:
SELECT en.*, e.*
FROM EMP_NEW en LEFT JOIN LATERAL
(SELECT EMP_ID
FROM EMP e
WHERE en.DEPT_ID = e.DEPT_ID AND en.EMP_UID = e.EMP_UID
ORDER BY (CASE WHEN en.SUB_DEPT_ID = e.SUB_DEPT_ID THEN 1 ELSE 2 END)
FETCH FIRST 1 ROW ONLY -- presumably you want only one row either way
) e

PostgreSQL 9.3: Pivot table query

I want to show the pivot table(crosstab) for the given below table.
Table: Employee
CREATE TABLE Employee
(
Employee_Number varchar(10),
Employee_Role varchar(50),
Group_Name varchar(10)
);
Insertion:
INSERT INTO Employee VALUES('EMP101','C# Developer','Group_1'),
('EMP102','ASP Developer','Group_1'),
('EMP103','SQL Developer','Group_2'),
('EMP104','PLSQL Developer','Group_2'),
('EMP101','Java Developer',''),
('EMP102','Web Developer','');
Now I want to show the pivot table for the above data as shown below:
Expected Result:
Employee_Number TotalRoles TotalGroups Available Others Group_1 Group_2
---------------------------------------------------------------------------------------------------
EMP101 2 2 1 1 1 0
EMP102 2 2 1 1 1 0
EMP103 1 2 1 0 0 1
EMP104 1 2 1 0 0 1
Explanation: I want to show the Employee_Number, the TotalRoles which each employee has,
the TotalGroups which are present to all employees, the Available shows the employee available
in how many groups, the Others have to show the employee is available in other's also for which
the group_name have not assigned and finally the Group_Names must be shown in the pivot format.
SELECT * FROM crosstab(
$$SELECT grp.*, e.group_name
, CASE WHEN e.employee_number IS NULL THEN 0 ELSE 1 END AS val
FROM (
SELECT employee_number
, count(employee_role)::int AS total_roles
, (SELECT count(DISTINCT group_name)::int
FROM employee
WHERE group_name <> '') AS total_groups
, count(group_name <> '' OR NULL)::int AS available
, count(group_name = '' OR NULL)::int AS others
FROM employee
GROUP BY 1
) grp
LEFT JOIN employee e ON e.employee_number = grp.employee_number
AND e.group_name <> ''
ORDER BY grp.employee_number, e.group_name$$
,$$VALUES ('Group_1'::text), ('Group_2')$$
) AS ct (employee_number text
, total_roles int
, total_groups int
, available int
, others int
, "Group_1" int
, "Group_2" int);
SQL Fiddle demonstrating the base query, but not the crosstab step, which is not installed on sqlfiddle.com
Basics for crosstab:
PostgreSQL Crosstab Query
Special in this crosstab: all the "extra" columns. Those columns are placed in the middle, after the "row name" but before "category" and "value":
Pivot on Multiple Columns using Tablefunc
Once again, if you have a dynamic set of groups, you need to build this statement dynamically and execute it in a second call:
Selecting multiple max() values using a single SQL statement
You can use the crosstab function for this.
First of all you need to add the tablefunc extension if you haven't already:
CREATE EXTENSION tablefunc;
The crosstab functions require you to pass it a query returning the data you need to pivot, then a list of the columns in the output. (In other ways "tell me the input and the output format you want"). The sort order is important!
In your case, the input query is quite complicated - I think you need to do a load of separate queries, then UNION ALL them to get the desired data. I'm not entirely sure how you calculate the values "TotalGroups" and "Available", but you can modify the below in the relevant place to get what you need.
SELECT * FROM crosstab(
'SELECT employee_number, attribute, value::integer AS value FROM (with allemployees AS (SELECT distinct employee_number FROM employee) -- use a CTE to get distinct employees
SELECT employee_number,''attr_0'' AS attribute,COUNT(distinct employee_role) AS value FROM employee GROUP BY employee_number -- Roles by employee
UNION ALL
SELECT employee_number,''attr_1'' AS attribute,value from allemployees, (select count (distinct group_name) as value from employee where group_name <> '''') a
UNION ALL
SELECT employee_number,''attr_2'' AS attribute, COUNT(distinct group_name) AS value FROM employee where group_name <> '''' GROUP BY employee_number -- Available, do not know how this is calculate
UNION ALL
SELECT a.employee_number, ''attr_3'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- other groups. Use a LEFT JOIN to avoid nulls in the output
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name ='''' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_4'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 1
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_1'' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_5'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 2
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_2'' GROUP BY employee_number) b on a.employee_number = b.employee_number) a order by 1,2')
AS ct(employee_number varchar,"TotalRoles" integer,"TotalGroups" integer,"Available" integer, "Others" integer,"Group_1" integer, "Group_2" integer)

Dividing one SQL column into subgroups with headings

I have two tables
STATUS
SNO | STATUS | DEPARTMENT_ID
1 In progress 1
2 Assigned 2
3 Quoted 2
4 Development 3
DEPARTMENTS
SNO | DEPARTMENT |
1 DESIGNING
2 MARKETING
3 PRODUCTION
Now I want a result like this using SQL stored procedure
Some Custom Column Name | DEPARTMENT_ID
DESIGNING -
In Progress 1
MARKETING -
Assigned 2
Quoted 2
PRODUCTION -
Development 3
The custom column will be used to populate a Telerik RadComboBox with DESIGNING, MARKETING and PRODUCTION acting as separators between statuses.
Select Department, -1 from Department_Table
Union
Select StatusName, Department_ID from Status_Table
Please elaborate your question so that we can provide better answer. Currently it seems you just want to return the joined data of both tables.
Often, this type of operation is more easily done at the application level. You can do it in SQL, using union all and order by, however:
select status as CustomColumnName, department
from ((select s.status, d.department, 1 as ordering
from status s join
departments d
on s.department_id = d.sno
) union all
(select d.department, NULL, 0 as ordering
from departments d
)
) dd
order by CustomColumnName, ordering;
Note: this treats the - as NULL.
Try this.Is it ok with other sample data ?
DECLARE #STATUS TABLE (
SNO INT
,[STATUS] VARCHAR(50)
,DEPARTMENT_ID INT
)
INSERT INTO #STATUS
VALUES (1,'In progress' ,1)
,(2,'Assigned',2)
,(3,'Quoted',2)
,(4,'Development',3)
DECLARE #DEPARTMENT TABLE (SNO INT,DEPARTMENT VARCHAR(50))
INSERT INTO #DEPARTMENT
VALUES ( 1,'DESIGNING'),(2,'MARKETING')
,(3,'PRODUCTION')
--select * from #STATUS
--select * from #DEPARTMENT
;
WITH CTE
AS (
SELECT DEPARTMENT [CustomeColumn]
,'-' DEPARTMENT_ID
,sno
FROM #DEPARTMENT
UNION ALL
SELECT [STATUS]
,cast(DEPARTMENT_ID AS VARCHAR(10))
,(
SELECT sno
FROM #DEPARTMENT
WHERE sno = a.DEPARTMENT_ID
)
FROM #STATUS A
)
SELECT *
FROM CTE
ORDER BY sno

Find Unmatch record 2 table with where condition apply and record show from 1 table

class table
class_code varchar(50)
timing varchar(50)
emp_id varchar(50)
employee table
i_id int
emp_id varchar(20)
name varchar(50)
We Have 2 tables 1 is employee and other is class
we have 4 records in employee table where emp_id=as-1,as-2,as-3,as-4
we have 2 records in class table with emp_id = as-1 or as-3 and timing= '3-4'
We select those record from employee table who available/free at timing='3-4' like as-2 or as-3 because as-1 or as-3 is already in class table in timing at 3-4
You have not told us a great deal and the indicated data may not be fully representative. Both of these will return employee 2 and 4 (& both will work in MySQL or MSsql):
SELECT
e.*
FROM employee e
LEFT JOIN class c
ON e.emp_id = c.emp_id
WHERE (c.timing <> '3-4'
OR c.timing IS NULL)
;
SELECT
*
FROM employee
WHERE NOT EXISTS (
SELECT 1
FROM class
WHERE timing = '3-4'
AND class.emp_id = employee.emp_id
)
;
see this sqlfiddle (MySQL)

How to write IN clause query to replace null for no value parameter

I am writing a query in which where clause have IN clause and there are large number of values in this IN clause , I want to fetch the result such that if there is no value exist in table for value given in IN clause then a raw containing 0 or null should return for that value. for example..
select age,sex,date_joining from emp where name IN ('amit','john','paul','dilip')
Now assume for this query ,data for john and paul does not exist in database then result should be like below..
21 male 21-AUG-2011
null null null
null null null
25 male 9-aug-2010
we can also have 0 instead of null if null is not possible
Thanks...
select filter.name
, emp.age
, emp.sex
, emp.date_joining
from (
values ('amit'), ('john'), ('paul'), ('dilip')
) filter(name)
left join
emp
on emp.name = filter.name
Live example at SQL Fiddle.
For older values of SQL Server, replace the line with values by:
from (
select 'amit'
union all select 'john'
union all select 'paul'
union all select 'dilip'
) filter(name)
You can also use common table expression to get this result:
;With AllEmpDetails as
(
Select [Name] from emp
UNION Select 'amit'
UNION Select 'john'
UNION Select 'paul'
UNION Select 'dilip'
)Select AllEmpDetails.Name, e2.Age, e2.Sex, e2.date_joining
from AllEmpDetails
Left Join emp e2 on e2.[Name] = AllEmpDetails.Name
In my database, I have already added details for amit and dilip so i have used UNION since you can easily get the detail about the available employees. On the other hand you can use UNION ALL with Distinct.