Recursive in Sql Server - sql

It is my test table
with test as
(select '1'as id, '2' as id_st, '324234234' as id_dd
union all
select
'1', '2', '43252345'
union all
select
'1', '2', '43252345'
union all
select
'1', '2', '43252344'
union all
select
'1', '2', '43252344323'
union all
select
'1', '2', '2345235'
union all
select
'2', null, '324234234'
union all
select
'2', null, '3432423'
union all
select
'2', null, '43252345'
union all
select
'2', null, '3432423234523'
union all
select
'2', null, '6543456'
union all
select
'2', null, '6543456754'
union all
select
'2', null, '43252344'
)
select *
into tmp_20102022v
from test;
And I was writing code for read recursive from table tmp_20102022v
WITH CTE
AS
(
SELECT distinct
M1.id id_t,
M1.id,
m1.id_dd
FROM tmp_20102022v M1
LEFT JOIN tmp_20102022v M2
ON M1.id = M2.id_st
WHERE M2.id IS NULL
UNION ALL
SELECT
C.id,
M.id_st,
m.id_dd
FROM CTE C
JOIN tmp_20102022v M
ON C.id = M.id
)
SELECT c.id_t,c.id_dd FROM CTe c
group by c.id_t,c.id_dd
Result this code:
How I need to change my code for gain result like below.
So that the result is id = 1 which includes id_dd as well as id = 1 and 2.
And id=2 which includes only id_dd for id=2:
The recursive tree can be large.

Related

Should I keep with 2 views, or can I combine into 1?

I currently have 2 views: t_sdet_part and t_sdet_part_all. t_sdet_part is pulling data from view table_mv, along with creating rows that don't already exist in table_mv. Then that data created is joined into another view to show all records (t_sdet_part_all). Below is my current code:
-- view created: t_sdet_part
WITH v as (
SELECT v.*
FROM table_mv v
)
SELECT d.s_date, ig.part_no, ig.i_group, l.s_level, ig.p_category,
COALESCE(v.qty_ordered, 0) as qty_ordered
FROM (SELECT DISTINCT s_date FROM v) d CROSS JOIN
(SELECT DISTINCT part_no, i_group, p_category FROM v) ig CROSS JOIN
(SELECT '80' as s_level FROM DUAL UNION ALL
SELECT '81' FROM DUAL UNION ALL
SELECT '95' FROM DUAL UNION ALL
SELECT '101' FROM DUAL UNION ALL
SELECT '100' FROM DUAL UNION ALL
SELECT 'Late' FROM DUAL
) l LEFT JOIN
v
ON v.s_date = d.s_date AND v.part_no = ig.part_no AND
v.i_group = ig.i_group AND v.s_level = l.s_level
ORDER BY s_date, part_no, i_group,
DECODE(s_level, '80', 1, '81', 2, '95', 3, '101', 4, '100', 5, 'Late', 6)
-- view created t_sdet_part_all
SELECT DISTINCT
t.s_date,
t.part_no,
t.i_group,
t.s_level,
t.p_category,
t.qty_ordered,
v.bucket,
v.relief_amt,
v.extreme_amt,
v.curr_mth_note,
v.carryover_note
FROM
t_sdet_part t
LEFT JOIN table_mv v ON t.s_date = v.s_date
AND t.part_no = v.part_no
ORDER BY
s_date,
part_no,
i_group,
DECODE(s_level, '80', 1, '81', 2, '95', 3, '101', 4, '100', 5, 'Late', 6)
They are both pulling and joining data from table_mv. I'm trying to find a way (if it's even possible) to combine both of the below files so I only have to create 1 new view instead of 2.

Error in Conditional UNION

I have this SQL:
SELECT MONTH(data) AS MES, cor, CASE month(data)
WHEN 1 THEN 'Janeiro' WHEN 2 THEN 'Fevereiro' WHEN 3 THEN 'Março' WHEN 4 THEN 'Abril' WHEN 5 THEN 'Maio' WHEN 6 THEN 'Junho' WHEN 7 THEN 'Julho' WHEN
8 THEN 'Agosto' WHEN 9 THEN 'Setembro' WHEN 10 THEN 'Outubro' WHEN 11 THEN 'Novembro' WHEN 12 THEN 'Dezembro' END AS MESCOR, COUNT(*)
AS Expr1, CASE cor WHEN 'AM' THEN '2' WHEN 'VD' THEN '1' WHEN 'VM' THEN '3' END AS Expr2
FROM TBINICIATIVAS_PREVISTAS
WHERE (login ='xxxxxxx')
GROUP BY MONTH(data), cor
UNION
SELECT '1', 'VD', 'Janeiro',0,'1'
UNION
SELECT '1', 'AM', 'Janeiro',0,'2'
UNION
SELECT '1', 'VM', 'Janeiro',0,'3'
ORDER BY expr2, mes
But I need the UNION to be conditional.
Something like:
if (select count(*) .... where cond1...) = 0
UNION
SELECT '1', 'VD', 'Janeiro',0,'1'
if (select count(*) ....where cond2...) = 0
UNION
SELECT '1', 'AM', 'Janeiro',0,'2'
if (select count(*) ....where cond3...) = 0
UNION
SELECT '1', 'VM', 'Janeiro',0,'3'
I tried, but I always got a syntax error.
Is it possible to do that?
Move your conditions to a WHERE clause inside each UNION's SELECT (you can't put anything other than a SELECT between UNION).
SELECT '1', 'VD', 'Janeiro',0,'0'
UNION
SELECT '1', 'VD', 'Janeiro',0,'1'
WHERE (select count(*) ....where cond1...) = 0
UNION
SELECT '1', 'AM', 'Janeiro',0,'2'
WHERE (select count(*) ....where cond2...) = 0
UNION
SELECT '1', 'VM', 'Janeiro',0,'3'
WHERE (select count(*) ....where cond3...) = 0
Also, I note from your conditions that you are checking if the row exists, by doing a count = 0. Replacing this with an actual NOT EXISTS will be faster because the SQL engine doesn't have to actually count all rows to compare against 0, it will return immediately when a row is found.
SELECT '1', 'VD', 'Janeiro',0,'0'
UNION
SELECT '1', 'VD', 'Janeiro',0,'1'
WHERE NOT EXISTS (select 1 ....where cond1...)
UNION
SELECT '1', 'AM', 'Janeiro',0,'2'
WHERE NOT EXISTS (select 1 ....where cond2...)
UNION
SELECT '1', 'VM', 'Janeiro',0,'3'
WHERE NOT EXISTS (select 1 ....where cond3...)

Oracle SQL - Form a dummy table from given strings to join with another table

There is N no. of strings.
let's say 'foo', 'bar', 'chi', 'xyz', 'moo'.
I want to form a dummy table, say X for joining with another table, say Y which has those strings in one of the column i.e name in . Trying to pull out data by running the below query.
select Y.name, Y.age
from(**select ('foo', 'bar', 'chi', 'xyz', 'moo') as name**) X
left join Y on X.name = Y.name;
I know that text within ** is not the proper SQL syntax, but looking for something similar to have to run query in Oracle SQL.
Any suggestion or ideas most welcome.
Use a VARRAY or collection and join on the COLUMN_VALUE pseudocolumn:
SELECT y.*
FROM TABLE( SYS.ODCIVARCHAR2LIST( 'foo', 'bar', 'chi', 'xyz', 'moo' ) ) t
INNER JOIN -- or LEFT OUTER JOIN
y
ON t.COLUMN_VALUE = y.name;
SYS.ODCIVARCHAR2LIST is one of several pre-existing VARRAYs but you can easily create your own collection:
CREATE TYPE Char3List IS TABLE OF CHAR(3)
/
SELECT y.*
FROM TABLE( Char3List( 'foo', 'bar', 'chi', 'xyz', 'moo' ) ) t
INNER JOIN -- or LEFT OUTER JOIN
y
ON t.COLUMN_VALUE = y.name;
or, with a collection (but not a VARRAY like SYS.ODCIVARCHAR2LIST), you don't even need to use a join:
SELECT *
FROM y
WHERE name MEMBER OF Char3List( 'foo', 'bar', 'chi', 'xyz', 'moo' );
You can even pass it in to a bind parameter as an array from an external language.
One simple method is union all:
select names.name, Y.age
from (select 'foo' as name from dual union all
select 'bar' as name from dual union all
select 'chi' as name from dual union all
select 'xyz' as name from dual union all
select 'moo' as name from dual
) names left join
Y
on names.name = Y.name;
Note that the select has changed to take the name from the first table, not the second (after all, there may be no match).
with names as (
select 'foo' as name from dual
union all
select 'bar' from dual
union all
select 'chi' from dual
union all
select 'xyz' from dual
union all
select 'moo' from dual
)
select x.name, y.age
from names x
left join y
on x.name = y.name;

SQL optimization for large data_sets

i got some nasty sql performance issue. I need to execute statment like:
SELECT *
FROM (SELECT /*+ FIRST_ROWS(26) */
a.*, ROWNUM rnum
FROM (SELECT *
FROM t1
WHERE t1_col1 = 'val1'
AND g_dom in ('1', '2', '3')
AND g_context IN ('3', '4', '5', '6')
AND i_col = 1
AND f_col in ('1', '2', '3', '4')
AND e_g IN (SELECT e_g
FROM t2
WHERE t2_col1 = 'val1'
AND g_context IN ('3', '4', '5', '6')
AND val like 'some val%')
ORDER BY order_id DESC) a)
WHERE rnum > 0;
Basically we got table t1 (our data table), and t2 (our support values). We got 1kk records in t1 and 10kk in t2. Column g_context narrows our data sets, but still, val had something like 500k records. We need 25 rows ordered by order_id.
Is there any way to tell inner statement
SELECT e_g FROM t2 WHERE t2_col1='val1' AND g_context IN('3','4','5','6' ) AND val like 'some val%
to get only 25 records that's match out outer statement criteria ?
Why not move rownum and the hint into the inner query like so:
SELECT t1.*,row_number() over (order by order_id desc) rn /*+ FIRST_ROWS(26) */
FROM t1
WHERE t1_col1 = 'val1'
AND g_dom in ('1', '2', '3')
AND g_context IN ('3', '4', '5', '6')
AND i_col = 1
AND f_col in ('1', '2', '3', '4')
AND e_g IN (SELECT e_g
FROM t2
WHERE t2_col1 = 'val1'
AND g_context IN ('3', '4', '5', '6')
AND val like 'some val%')
ORDER BY order_id DESC
Too me this extra subselect with hint and rownum does not seem to make any sense.
And the where-clause should be "WHERE rnum < 26", shouldn't it?

Finding matches in multiple columns in different orders

I am trying to merge 2 databases with the same schema together, and this is one part of it.
I have changed the subject to keep it more understandable - I cannot change this schema, it's just what I'm working with.
I have a table in both my source and target databases with the following columns:
Car
CarType1
CarType2
CarType3
CarType4
I am trying to write a query that will tell me in the target database, which rows have the same Cars between the 2 databases, but different CarTypes. All I need is a count on the rows that are different.
My query written in english would be:
Bring me back a count of rows where the Car is the same and the CarTypes between the two systems do not match. It doesn't matter if the CarType is in a different CarType field between the two, just whether all of the values are contained in one of the 4 fields or not.
So if in my source database this row:
Car: Mustang
CarType1: Fast
CarType2: Convertible
CarType3: null
CarType4: null
And in my target database I have this row:
Car: Mustang
CarType1: Fast
CarType2: Convertible
CarType3: Sports
CarType4: null
This would count as a non-match, since it's a Mustang and because the aggregate of the CarType fields is different. What order the values are in does not matter for this.
How would I write this query? I cannot get a grasp on it.
;WITH SourceT AS (
SELECT 'Toyota' AS Car, 'A' AS CarType1, 'B' AS CarType2, 'C' CarType3, 'D' CarType4 UNION ALL
SELECT 'BMW' AS Car, 'A' AS CarType1, 'B' AS CarType2, 'C' CarType3, 'D' CarType4 UNION ALL
SELECT 'Mustang' AS Car, 'Fast' AS CarType1, 'Convertible' AS CarType2, 'Sports' CarType3, NULL CarType4
),
TargetT AS (
SELECT 'Toyota' AS Car, 'D' AS CarType1, 'C' AS CarType2, 'B' CarType3, 'A' CarType4 UNION ALL
SELECT 'BMW' AS Car, 'D' AS CarType1, 'C' AS CarType2, 'B' CarType3, 'A' CarType4 UNION ALL
SELECT 'Mustang' AS Car, 'Fast' AS CarType1, 'Convertible' AS CarType2, NULL CarType3, NULL CarType4 )
SELECT *
FROM SourceT s
WHERE NOT EXISTS
(
SELECT *
FROM TargetT t
WHERE s.Car = t.Car AND 0 =
(SELECT COUNT(*) FROM
( (
(SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t )
EXCEPT
(SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t )
)
UNION ALL
(
(SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t )
EXCEPT
(SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t )
)
) T
)
)
Or a slightly shorter version
SELECT *
FROM SourceT s
WHERE NOT EXISTS
(
SELECT *
FROM TargetT t
WHERE s.Car = t.Car AND
(SELECT t FROM (SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t ) D ORDER BY t FOR XML PATH(''))=
(SELECT t FROM (SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t ) D ORDER BY t FOR XML PATH(''))
)
Try this and let me know if it works:
SELECT * FROM db1.dbo.Cars
EXCEPT
SELECT c1.* FROM db1.dbo.Cars as c1
INNER JOIN db2.dbo.Cars as c2
ON c1.Car = c2.Car
AND
--Check carType1
(c1.CarType1 = c2.CarType1 OR
c1.CarType1 = c2.CarType2 OR
c1.CarType1 = c2.CarType3 OR
c1.CarType1 = c2.CarType4)
AND
--Check carType2
(c1.CarType2 = c2.CarType1 OR
c1.CarType2 = c2.CarType2 OR
c1.CarType2 = c2.CarType3 OR
c1.CarType2 = c2.CarType4)
AND
--Check carType3
(c1.CarType3 = c2.CarType1 OR
c1.CarType3 = c2.CarType2 OR
c1.CarType3 = c2.CarType3 OR
c1.CarType3 = c2.CarType4)
AND
--Check carType4
(c1.CarType4 = c2.CarType1 OR
c1.CarType4 = c2.CarType2 OR
c1.CarType4 = c2.CarType3 OR
c1.CarType4 = c2.CarType4)
NOTE:
You will have to add ISNULLs to this to either include or exclude if a column is null.
To exclude:
ISNULL(c1.CarType4, -1) = ISNULL(c2.CarType4, -2)
To include:
ISNULL(c1.CarType4, -1) = ISNULL(c2.CarType4, -1)
SELECT c1.car
FROM target.cars c1
INNER JOIN source.cars c2
ON c2.car = c1.car
WHERE
COALESCE( c1.cartype1, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype2, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype3, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype4, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
LEN( COALESCE( c1.cartype1, '') + COALESCE( c1.cartype2, '') +
COALESCE( c1.cartype3, '') + COALESCE( c1.cartype4, '') )
<>
LEN( COALESCE( c2.cartype1, '') + COALESCE( c2.cartype2, '') + COALESCE( c2.cartype3, '') +
COALESCE( c2.cartype4, '') )
;