here is the table for reference
CREATE TABLE XX_EMPLOYEES
(
EMP_ID NUMBER NOT NULL,
EMP_FIRST_NAME VARCHAR2(250) NOT NULL,
EMP_MIDDLE_NAME VARCHAR2(250) NOT NULL,
EMP_LAST_NAME VARCHAR2(250) NOT NULL,
Hired_Date DATE NOT NULL,
Country VARCHAR2(250) NOT NULL,
Salary NUMBER NOT NULL
);
INSERT ALL
INTO XX_EMPLOYEES (EMP_ID, EMP_FIRST_NAME, EMP_MIDDLE_NAME, EMP_LAST_NAME, Hired_Date, Country, Salary) VALUES (1,'Tomm','Jef','Adam','01-Jan-2016','JORDAN',1000)
INTO XX_EMPLOYEES (EMP_ID, EMP_FIRST_NAME, EMP_MIDDLE_NAME, EMP_LAST_NAME, Hired_Date, Country, Salary) VALUES (2,'Mohammed','Ahmed','Mahmoud','15-Jul-2009','UAE',900)
INTO XX_EMPLOYEES (EMP_ID, EMP_FIRST_NAME, EMP_MIDDLE_NAME, EMP_LAST_NAME, Hired_Date, Country, Salary) VALUES (4,'Ali','Ahmad','Mahmoud','07-Jul-2000','UK',1200)
INTO XX_EMPLOYEES (EMP_ID, EMP_FIRST_NAME, EMP_MIDDLE_NAME, EMP_LAST_NAME, Hired_Date, Country, Salary) VALUES (10,'Basel','Jamal','Saeed','10-Apr-2001','UAE',1000)
SELECT * FROM dual;
I want to use XMLAGG function to return the employee full information in one line, concatenated by #$#
I have used loop function to do it and RTRIM but I need to use XMLAGG. Is it possible?
Result should be like this:
1,Tomm,Jef,Adam,01-JAN-2016,JORDAN,1000 #$# 2,Mohammed,Ahmed,Mahmoud,15-JUL-2009,UAE,900 #$# 4,Ali,Ahmad,Mahmoud,07-JUL-2000,UK,1200 #$# 10,Basel,Jamal,Saeed,10-APR-2001,UAE,1000
Statement processed.
If the final result doesn't exceed 4000 characters, listagg is simpler to use:
SQL> WITH
2 one_emp
3 AS
4 (SELECT emp_id
5 || ','
6 || emp_first_name
7 || ','
8 || emp_middle_name
9 || ','
10 || emp_last_name
11 || ','
12 || hired_date
13 || ','
14 || country
15 || ','
16 || salary AS one_employee
17 FROM xx_employees)
18 SELECT LISTAGG (one_employee, '#$#') WITHIN GROUP (ORDER BY NULL) AS result
19 FROM one_emp;
RESULT
--------------------------------------------------------------------------------
1,Tomm,Jef,Adam,01.01.16,JORDAN,1000#$#10,Basel,Jamal,Saeed,10.04.01,UAE,1000#$#
2,Mohammed,Ahmed,Mahmoud,15.07.09,UAE,900#$#4,Ali,Ahmad,Mahmoud,07.07.00,UK,1200
If the result is longer than 4000 characters (which might be, if there are many employees involved) or you just want to use xmlagg, then
SQL> WITH
2 one_emp
3 AS
4 (SELECT emp_id
5 || ','
6 || emp_first_name
7 || ','
8 || emp_middle_name
9 || ','
10 || emp_last_name
11 || ','
12 || hired_date
13 || ','
14 || country
15 || ','
16 || salary AS one_employee
17 FROM xx_employees)
18 SELECT RTRIM (
19 XMLAGG (XMLELEMENT (e, one_employee || '#$#') ORDER BY NULL).EXTRACT (
20 '//text()'),
21 '#$#') AS result
22 FROM one_emp;
RESULT
--------------------------------------------------------------------------------
1,Tomm,Jef,Adam,01.01.16,JORDAN,1000#$#2,Mohammed,Ahmed,Mahmoud,15.07.09,UAE,900
#$#4,Ali,Ahmad,Mahmoud,07.07.00,UK,1200#$#10,Basel,Jamal,Saeed,10.04.01,UAE,1000
SQL>
It isn't too difficult to convert that code into a function:
SQL> CREATE OR REPLACE FUNCTION f_test
2 RETURN CLOB
3 IS
4 retval CLOB;
5 BEGIN
6 WITH
7 one_emp
8 AS
9 (SELECT emp_id
10 || ','
11 || emp_first_name
12 || ','
13 || emp_middle_name
14 || ','
15 || emp_last_name
16 || ','
17 || hired_date
18 || ','
19 || country
20 || ','
21 || salary AS one_employee
22 FROM xx_employees)
23 SELECT LISTAGG (one_employee, '#$#') WITHIN GROUP (ORDER BY NULL)
24 INTO retval
25 FROM one_emp;
26
27 RETURN retval;
28 END;
29 /
Function created.
Let's try it:
SQL> select f_test from dual;
F_TEST
--------------------------------------------------------------------------------
1,Tomm,Jef,Adam,01.01.16,JORDAN,1000#$#10,Basel,Jamal,Saeed,10.04.01,UAE,1000#$#
2,Mohammed,Ahmed,Mahmoud,15.07.09,UAE,900#$#4,Ali,Ahmad,Mahmoud,07.07.00,UK,1200
SQL>
Without a CTE and without RTRIM:
SQL> SELECT XMLAGG (XMLELEMENT (
2 e,
3 emp_id
4 || ','
5 || emp_first_name
6 || ','
7 || emp_middle_name
8 || ','
9 || emp_last_name
10 || ','
11 || hired_date
12 || ','
13 || country
14 || ','
15 || salary
16 || '#$#')
17 ORDER BY NULL).EXTRACT ('//text()') AS result
18 FROM xx_employees;
RESULT
--------------------------------------------------------------------------------
1,Tomm,Jef,Adam,01.01.16,JORDAN,1000#$#2,Mohammed,Ahmed,Mahmoud,15.07.09,UAE,900
#$#4,Ali,Ahmad,Mahmoud,07.07.00,UK,1200#$#10,Basel,Jamal,Saeed,10.04.01,UAE,1000
#$#
SQL>
Consider the following table
ID || YEAR || TERM || NAME || UNIT
----------------------------------------
1 || 1985 || 1 || MARIE || 01VS
1 || 1986 || 2 || MARIE || 01VS
1 || 1986 || 2 || MARIE || 07GB
1 || 1986 || 3 || MARIE || 07GB
2 || 1992 || 1 || AVALON || 01VS
2 || 1992 || 2 || AVALON || 01VS
2 || 1992 || 3 || AVALON || 01VS
3 || 2001 || 1 || DENIS || 08HK
3 || 2001 || 1 || DENIS || 07GB
3 || 2001 || 2 || DENIS || 08HK
3 || 2002 || 1 || DENIS || 08HK
I wanted to write a sql query in H2 which would return all rows for each ID in which YEAR and TERM have equal values. So for the table above the result should be like below:
ID || YEAR || TERM || NAME || UNIT
----------------------------------------
1 || 1986 || 2 || MARIE || 01VS
1 || 1986 || 2 || MARIE || 07GB
3 || 2001 || 1 || DENIS || 08HK
3 || 2001 || 1 || DENIS || 07GB
You can use exists :
select t.*
from table t
where exists (select 1
from table t1
where t1.id = t.id and t1.year = t.year and
t.term = t1.term and t1.unit <> t.unit
);
Something like the below would work I think
select *
from table t
where exists (select id, term from table t2
where t2.id = t.id
and t2.term = t.term
group by id, term
having count(*) > 1)
However it would be easier if the table had a primary key of some sort.
How about joining the table to a subquery with GROUP BY and a HAVING ?
select t.*
from yourtable t
join
(
select ID, YEAR, TERM
from yourtable
group by ID, YEAR, TERM
having count(*) > 1
) d on (d.ID = t.ID and d.YEAR = t.YEAR and d.TERM = t.TERM);
I tried to do a little research on this, but didn't have much luck.
I have a date (MMDDYY format) stored in a varchar field (DateValue) in a table that looks something similar to this:
TableA
--------------------------------------------------------------------------------------------------------
----------------------
|| ID | DateValue ||
----- -----------
|| 1 | 011212 ||
|| 2 | 011549 ||
|| 3 | 070860 ||
--------------------------------------------------------------------------------------------------------
I am trying to add another column ConvertDateValue to the same table which would be a date field. The values in this column would be converted values from DateValue field in this format (YYYY-MM-DD). Here is what I have tried:
--declare table variable
declare #tableA table (ID int, DateValue varchar(50))
--insert sample values into table variable
insert into #tableA VALUES
(1,'011212'),
(2,'011549'),
(3,'070860')
begin
select ID,
DateValue,
CAST(STUFF(STUFF(DateValue, 3, 0, '-'), 6, 0, '-') as date) as ConvertDateValue
from #tableA
end
Output:
|| ID | DateValue || ConvertedDateValue ||
----- ----------- ------------------
|| 1 | 011212 || 2012-01-12 ||
|| 2 | 011549 || 2049-01-15 ||
|| 3 | 070860 || 1960-07-08 ||
Expected Output:
|| ID | DateValue || ConvertedDateValue ||
----- ----------- ------------------
|| 1 | 011212 || 2012-01-12 ||
|| 2 | 011549 || 2049-01-15 ||
|| 3 | 070860 || 2060-07-08 || --Here is the difference
I need to ensure that the ConvertedDateValue is displaying correct century. The above value could also be 1960-07-08 for some data and not for others.
FYI, I am aware of the two year cutoff date option and we have the default
value set for that i.e. year 2049. Unfortunately, I am not allowed to change any of the advanced option settings for various reasons.
I am open to feedback and what alternatives are out there? Thanks in advance!
That's pretty awesome, here is the substring to fix it:
select convert(date, cast(substring(DateValue,1,2) + '/' + substring(DateValue,3,2) + '/20' + substring(DateValue,5,2) as datetime), 101 ) as converteddate
The convert isn't really necessary to populate the db, but it's the format you asked for.
Just manually parse the date and use a CASE statement to determine the century. If you want '070860' to sometimes be 2060-07-08, and other times to be 1960-07-08 then what logic besides the 2 digit year do you have to determine the century?
--declare table variable
declare #tableA table (ID int, DateValue varchar(50))
DECLARE #Month int
DECLARE #Day int
DECLARE #Year int
--insert sample values into table variable
insert into #tableA VALUES
(1,'011212'),
(2,'011549'),
(3,'070860')
begin
select ID,
DateValue,
(CONVERT(varchar(4), CASE
WHEN CAST(SUBSTRING(DateValue, 5, 2) AS int) > 88 THEN 1900 + CAST(SUBSTRING(DateValue, 5, 2) AS int)
ELSE 2000 + CAST(SUBSTRING(DateValue, 5, 2) AS int)
END)
+ '-' + SUBSTRING(DateValue, 1, 2) + '-' + SUBSTRING(DateValue, 3, 2))
as ConvertDateValue
from #tableA
end
Output
|| ID | DateValue || ConvertedDateValue ||
----- ----------- ------------------
|| 1 | 011212 || 2012-01-12 ||
|| 2 | 011549 || 2049-01-15 ||
|| 3 | 070860 || 2060-07-08 ||
I need a hint in order to solve this SQL (self-join) problem:
a table, with columns value and category
id || value || category || foo
------------------------------------
1 || 1 || a || 1
2 || 2 || a || 4
3 || 3 || a || 2
4 || 0 || b || 2
5 || 1 || b || 1
6 || 2 || b || 4
7 || 3 || b || 2
8 || 4 || b || 2
9 || 5 || b || 1
10 || 5 || b || 4
11 || 6 || b || 2
12 || 99 || z || 2
I would like to compare all values from category b and all values from category a and get all values that are in b and not in a or their id, so:
(0,1,2,3,4,5,5,6) "compare" (1,2,3) => (0,4,5,5,6)
ANSI SQL:
SELECT
*
FROM
tbl
WHERE
category = 'b'
AND value NOT IN (SELECT value FROM tbl WHERE category = 'a')
See it live here.
Start analyzing your task: "get all values that are in b and not in a or their id"
get all values > SELECT value FROM mytable
that are in b > WHERE category = 'b'
and not in a > AND value NOT IN (SELECT value FROM mytable WHERE category = 'a')
or their id - what should this mean?