I'm trying to figure out how to write a SQL query that returns the result of two other SELECT statements, each with their own JOIN. Here's the scenario:
Table1 might have NULL values in the T1Number and/or T1State columns. Table2 might have rows with a matching number or state. I want all rows from Table1, but want to fill in any NULL T1Number with T2Number when the states match, and fill in any NULL T1State with T2State when the numbers match. I don't want rows from Table2 that don't have a matching state or number:
Table1: Table2:
Name T1Number T1State T2Number T2State
---- -------- ------- -------- -----
Joe 1 NULL 1 MA
Bob NULL CA 2 CA
Dan NULL NULL 3 FL
Sam 4 NY 4 NY
Ray 5 TX 8 PA
So I have one SELECT statement to get the Number:
SELECT
Table1.Name,
Table1.T1Number,
Table1.T1State,
Table2.T2Number,
Table2.T2State
FROM Table1
INNER JOIN Table2 ON Table2.T2State = Table1.T1State
WHERE (Table1.T1Number IS NULL OR Table1.T1State IS NULL)
Result:
Name T1Number T1State T2Number T2State
---- -------- ------- -------- -------
Bob NULL CA 2 CA
And another SELECT statement to get the State:
SELECT
Table1.Name,
Table1.T1Number,
Table1.T1State
Table2.T2Number
Table2.T2State
FROM Table1
INNER JOIN Table2 ON Table2.T2Number = Table1.T1Number
WHERE (Table1.T1Number IS NULL OR Table1.T1State IS NULL)
Result:
Name T1Number T1State T2Number T2State
---- -------- ------- -------- -------
Joe 1 NULL 1 MA
How do I write a combined SELECT statement that gives me the following desired result?
Name Number State
---- ------ -----
Joe 1 MA
Bob 2 CA
Dan NULL NULL
Sam 4 NY
Ray 5 TX
I assume I need a containing SELECT statement that does a LEFT JOIN between Table1 and the union of the above queries, but I know this is way easier than I'm making it. Many thanks in advance.
You could use a single select statement without the where clause and a case statement in your join operation. Something like:
SELECT t1.Name
, CASE WHEN t1.Number is null then t2.Number else t1.Number END as Number
, CASE WHEN t1.State is null then t2.State else t1.State end as State
FROM Table1 t1
LEFT JOIN Table2 t2
ON CASE WHEN t1.Number is null THEN t1.State
ELSE CONVERT(varchar(1), t1.Number) END
= CASE WHEN t1.Number is null THEN tab2.State
ELSE CONVERT(varchar(1), t2.Number) END
Related
Need your help in getting the SQL Query.
1. I have one table which is having following columns
Name Null? Type
------------ -------- ------------
EMP_ID NOT NULL NUMBER(2)
DEP_ID NUMBER(2)
SALARY NUMBER(14,3)
NAME1 VARCHAR2(50)
NAME2 VARCHAR2(50)
JOINING_DATE DATE
Now I want the result - COUNT(1) based on DEP_ID without using GROUP BY .
EXAMPLE :
select DEP_ID,COUNT(1) from unipartemp group by DEP_ID;
DEP_ID COUNT(1)
1 2
2 2
3 1
What is the Query where we should get the same result but we should not use group by ...
Please suggest .
I am assuming that the result u r looking for is the count of the distinct dept_id. Try using the distinct(dept_id) to get the result.
I have a table with two type of scenario below:
Scenario A: Active employee has one row of DateJoin data
---- ---- ----
Name Column Value
---- ---- ----
Emp A DateJoin 20190701
Scenario B: Resigned employee will has its DateJoin data empty, inserted new row call ResignDate
---- ---- ----
Name Column Value
---- ---- ----
Emp A DateJoin NULL
Emp A ResignDate 20190702
For first scenario, it's straight forward, I just need to get the value of the row. But for second scenario, DateJoin will be empty so I must get ResignDate as the value.
I'm trying to achieve this with below query (not a working query):
SELECT e.Name,
-- Not working due to syntax error in CASE
CASE WHEN LEN(SELECT Value FROM ed WHERE Column = 'DateJoin') > 0
THEN SELECT Value FROM ed WHERE Column = 'DateJoin'
ELSE SELECT Value FROM ed WHERE Column = 'ResignDate'
END AS EmpDate
FROM employee e
INNER JOIN employee_date ed ON e.Name = ed.Name
How do I achieve above with CASE? Or is there any better idea to achieve it?
Depending on the complexity of the data - I came up with below that you can use as the starting point
DROP TABLE IF EXISTS #t
SELECT 'emp A' AS [name] , 'datejoin' AS col , CAST('20190701' AS DATE) AS value
INTO #t
INSERT INTO #t
SELECT
'emp B',
'datejoin',
NULL
INSERT INTO #t
SELECT
'emp B',
'Resign',
'20190703'
SELECT name , MAX(value) AS date
FROM #t GROUP BY name
;WITH temp AS (
SELECT * , ROW_NUMBER() OVER ( PARTITION BY name ORDER BY value DESC ) AS rn FROM #t
)
SELECT temp.name , temp.col , temp.value
FROM temp
WHERE rn = 1
I have a UDTF that will always return 1 row of 6 columns
The UDTF has one parameter
I want the 5 columns included in the result set of a query. The table I'm querying has a column that I want to use as the parameter for each row
I have not been able to figure out the correct syntax.
Any suggestions?
The UDTF
create function xxxx.UF_yyyyyy(USERID CHAR(10))
returns table (
p2User char(10),
STATUS CHAR(3),
USED DEC(7, 0),
CREATED DEC(7, 0),
SIGNON DEC(7, 0),
EXCLUDE DEC(7, 0))
language RPGLE
NOT DETERMINISTIC
NO SQL
DISALLOW PARALLEL
NOT FENCED
EXTERNAL NAME 'xxxx/UF_yyyyyy'
PARAMETER STYLE DB2SQL
example
select * from table(xxxx/UF_yyyyyy(CHAR('CMFIRST '))) a
result
P2USER STATUS USED CREATED SIGNON EXCLUDE
---------- ------ ------- ------- ------- -------
CMFIRST ACT 1170926 1150826 1170926 0
Here is an example of a select I tried
SELECT T1.AQABVN, T1.AQA8TX,
(SELECT COUNT(*) FROM fffff T4 WHERE T4.BDABVN = T1.AQABVN) AS SACCMS,
t2.p2User, t2.used
FROM
zzzzz T1
full join table(xxxx.UF_yyyyyy(T1.AQABVN)) t2 on T1.AQABVN = t2.p2User
Result
[SQL0205] Column P2USER not in table T2 in *N.
Got it working
SELECT T1.AQABVN, T1.AQA8TX,
(SELECT COUNT(*) FROM fffff T4 WHERE T4.BDABVN = T1.AQABVN) AS SACCMS,
t2.status, t2.used, t2.created, t2.signon, t2.exclude
FROM
zzzzz T1
join
table(SMLFQA.UF_XAJKUPR(T1.AQABVN)) t2 on T1.AQABVN = t2.p2User
I'm working with a database that have a poor design that does not constraint duplicates rows as long as they have a different unique-identifier.
Within one of the table, a given user can have an attribute and a value for the attribute. Normally, a user would only a have a single time the attribute but because of the poor design, I'm getting a lot of duplicates in the table and now I need to clean that mess. This is due to the CRM software not always checking if the row exists when we modify the employee profile but instead it creates a bunch of new rows with duplicates values.
The following query returns the duplicates values:
SELECT ua.ID AS LineID
,ua.Modified AS LineLastModifiedDate
,u.FullName AS EmployeeName
,a.Name AS AttributeName
,ua.value AS AttributeValue
FROM UserAttributes AS ua
INNER JOIN Users AS u ON ua.userid = u.id
INNER JOIN Attributes AS a ON ua.AttributeID = a.ID
WHERE EXISTS (
SELECT NULL
FROM UserAttributes as ua2
WHERE ua2.UserID = ua.UserID
AND ua2.AttributeID = ua.AttributeID
AND ua2.ID != ua.ID
)
And produces results as this:
LineID LineLastModifiedDate EmployeeName AttributeName AttributeValue
------ ----------------------- ------------- --------------- ---------------
15 2016-01-01 Employee1 EmployeeNumber 15
19 2016-07-20 Employee1 EmployeeNumber 15
35 2016-01-01 Employee2 EmployeeSex M
96 2016-07-20 Employee2 EmployeeSex M
21 2016-03-03 Employee1 SickDays 3
99 2016-07-10 Employee1 SickDays 5
What I need to accomplish starting from this query is : ForEach grouping of the same EmployeeName and AttributeName, give me the last modified line expecting results like this :
LineID LineLastModifiedDate EmployeeName AttributeName AttributeValue
------ ----------------------- ------------- --------------- ---------------
19 2016-07-20 Employee1 EmployeeNumber 15
96 2016-07-20 Employee2 EmployeeSex M
99 2016-07-10 Employee1 SickDays 5
How can I modify my query to accomplish this ?
Thank you
-M
;WITH CTE
AS
(
SELECT ua.ID AS LineID
,ua.Modified AS LineLastModifiedDate
,u.FullName AS EmployeeName
,a.Name AS AttributeName
,ua.value AS AttributeValue
,ROW_NUMBER() OVER (PARTITION BY EMPLOYEENAME,EMPLOYEESEX ORDER BY UA.Modified DESC) AS RN
FROM UserAttributes AS ua
INNER JOIN Users AS u ON ua.userid = u.id
INNER JOIN Attributes AS a ON ua.AttributeID = a.ID
WHERE EXISTS (
SELECT NULL
FROM UserAttributes as ua2
WHERE ua2.UserID = ua.UserID
AND ua2.AttributeID = ua.AttributeID
AND ua2.ID != ua.ID
)
)
SELECT * FROM cte where rn=1
You can use row numbering or a scheme as below where you pull out the max value and then use a join. Presumably you can't have ties by date.
select ...
from
UserAttributes as ua
inner join
(
select
UserID, AttributeID,
max(LineLastModifiedDate) as MaxLineLastModifiedDate
fromUserAttributes
group by UserId
) as max_ua
on max_ua.UserID = ua.UserID
and max_ua.AttributeID = max_ua.AttributeID
and max_ua.MaxLineLastModifiedDate = ua.LineLastModifiedDate
...
DNO DNAME
----- -----------
1 Research
2 Finance
EN ENAME CITY SALARY DNO JOIN_DATE
-- ---------- ---------- ---------- ---------- ---------
E1 Ashim Kolkata 10000 1 01-JUN-02
E2 Kamal Mumbai 18000 2 02-JAN-02
E3 Tamal Chennai 7000 1 07-FEB-04
E4 Asha Kolkata 8000 2 01-MAR-07
E5 Timir Delhi 7000 1 11-JUN-05
//find all departments that have more than 3 employees.
My try
select deptt.dname
from deptt,empl
where deptt.dno=empl.dno and (select count(empl.dno) from empl group by empl.dno)>3;
here is the solution
select deptt.dname
from deptt,empl
where deptt.dno=empl.dno
group by deptt.dname having count(1)>3;
select
*
from departments d
inner join (
select dno from employees group by dno having count(*) > 3
) e on d.dno = e.dno
There are many approaches to this problem but almost all will use GROUP BY and the HAVING clause. That clause allows you to filter results of aggregate functions. Here it is used to choose only those records where the count is greater than 3.
In the query structure used above the group by is handled on the employee table only, then the result (which is known as a derived table) is joined by an INNER JOIN to the departments table. This inner join only allows matching records so this has the effect of filtering the departments table to only those which have a count() of greater than 3.
An advantage of this query structure is fewer records are joined, and also that all columns of the departments table are available for reporting. Disadvantage of this structure is the the count() of employees per department isn't visible.