sql - मैं ओरेकल में किसी तालिका में डुप्लिकेट मान कैसे प्राप्त करूं?




oracle duplicate-data (11)

सरल मैं सोच सकता हूं:

select job_number, count(*)
from jobs
group by job_number
having count(*) > 1;

सबसे सरल SQL कथन क्या है जो किसी दिए गए कॉलम के लिए डुप्लिकेट मान और ओरेकल डेटाबेस तालिका में उनकी घटनाओं की गणना करेगा?

उदाहरण के लिए: मेरे पास कॉलम JOB_NUMBER साथ JOBS तालिका है। मैं कैसे पता लगा सकता हूं कि मेरे पास कोई डुप्लिकेट JOB_NUMBER एस है, और कितनी बार उन्हें डुप्लिकेट किया गया है?


यदि आपको डुप्लीकेट की वास्तविक संख्या जानने की आवश्यकता नहीं है, तो आपको लौटाए गए कॉलम में भी गिनती की आवश्यकता नहीं है। जैसे

SELECT column_name
FROM table
GROUP BY column_name
HAVING COUNT(*) > 1

SELECT   SocialSecurity_Number, Count(*) no_of_rows
FROM     SocialSecurity 
GROUP BY SocialSecurity_Number
HAVING   Count(*) > 1
Order by Count(*) desc 

कैसा रहेगा:

SELECT <column>, count(*)
FROM <table>
GROUP BY <column> HAVING COUNT(*) > 1;

उपर्युक्त उदाहरण का उत्तर देने के लिए, यह इस तरह दिखेगा:

SELECT job_number, count(*)
FROM jobs
GROUP BY job_number HAVING COUNT(*) > 1;

1. समाधान

select * from emp
    where rowid not in
    (select max(rowid) from emp group by empno);

करते हुए

select count(j1.job_number), j1.job_number, j1.id, j2.id
from   jobs j1 join jobs j2 on (j1.job_numer = j2.job_number)
where  j1.id != j2.id
group by j1.job_number

आपको डुप्लिकेट पंक्तियों 'आईडी देगा।


यदि एकाधिक कॉलम अद्वितीय पंक्ति (जैसे संबंध तालिका) की पहचान करते हैं तो आप निम्न का उपयोग कर सकते हैं

पंक्ति आईडी का प्रयोग करें जैसे emp_dept (empid, deptid, startdate, enddate) मान लीजिए एम्पिड और डेप्टिड अद्वितीय हैं और उस मामले में पंक्ति की पहचान करें

select oed.empid, count(oed.empid) 
from emp_dept oed 
where exists ( select * 
               from  emp_dept ied 
                where oed.rowid <> ied.rowid and 
                       ied.empid = oed.empid and 
                      ied.deptid = oed.deptid )  
        group by oed.empid having count(oed.empid) > 1 order by count(oed.empid);

और यदि ऐसी तालिका में प्राथमिक कुंजी है तो पंक्ति के बजाय प्राथमिक कुंजी का उपयोग करें, उदाहरण के लिए आईडी पीके है

select oed.empid, count(oed.empid) 
from emp_dept oed 
where exists ( select * 
               from  emp_dept ied 
                where oed.id <> ied.id and 
                       ied.empid = oed.empid and 
                      ied.deptid = oed.deptid )  
        group by oed.empid having count(oed.empid) > 1 order by count(oed.empid);

select column_name, count(column_name)
from table
group by column_name
having count (column_name) > 1;

इसके अलावा आप तालिका में सभी डुप्लिकेट मानों को सूचीबद्ध करने के लिए कुछ ऐसा करने का प्रयास कर सकते हैं reqitem

SELECT count(poid) 
FROM poitem 
WHERE poid = 50 
AND rownum < any (SELECT count(*)  FROM poitem WHERE poid = 50) 
GROUP BY poid 
MINUS
SELECT count(poid) 
FROM poitem 
WHERE poid in (50)
GROUP BY poid 
HAVING count(poid) > 1;

मैं आमतौर पर ओरेकल विश्लेषणात्मक समारोह ROW_NUMBER() उपयोग करता हूं।

मान लें कि आप एक अद्वितीय इंडेक्स या स्तंभों ( c1 , c2 , c3 ) पर निर्मित प्राथमिक कुंजी के संबंध में आपके पास डुप्लीकेट देखना चाहते हैं। फिर आप इस तरह से जाएंगे, पंक्तियों के ROWID लाएंगे जहां ROW_NUMBER() द्वारा लाई गई रेखाओं की संख्या >1 :

Select * From Table_With_Duplicates
      Where Rowid In
                    (Select Rowid
                       From (Select Rowid,
                                    ROW_NUMBER() Over (
                                            Partition By c1 || c2 || c3
                                            Order By c1 || c2 || c3
                                        ) nbLines
                               From Table_With_Duplicates) t2
                      Where nbLines > 1)

मैं अपने पदानुक्रमों के लिए बंद तालिकाओं के साथ PostgreSQL का उपयोग कर रहा हूँ। मेरे पास पूरे डेटाबेस के लिए एक सार्वभौमिक संग्रहीत प्रक्रिया है:

CREATE FUNCTION nomen_tree() RETURNS trigger
    LANGUAGE plpgsql
    AS $_$
DECLARE
  old_parent INTEGER;
  new_parent INTEGER;
  id_nom INTEGER;
  txt_name TEXT;
BEGIN
-- TG_ARGV[0] = name of table with entities with PARENT-CHILD relationships (TBL_ORIG)
-- TG_ARGV[1] = name of helper table with ANCESTOR, CHILD, DEPTH information (TBL_TREE)
-- TG_ARGV[2] = name of the field in TBL_ORIG which is used for the PARENT-CHILD relationship (FLD_PARENT)
    IF TG_OP = 'INSERT' THEN
    EXECUTE 'INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT $1.id,$1.id,0 UNION ALL
      SELECT $1.id,ancestor_id,depth+1 FROM ' || TG_ARGV[1] || ' WHERE child_id=$1.' || TG_ARGV[2] USING NEW;
    ELSE                                                           
    -- EXECUTE does not support conditional statements inside
    EXECUTE 'SELECT $1.' || TG_ARGV[2] || ',$2.' || TG_ARGV[2] INTO old_parent,new_parent USING OLD,NEW;
    IF COALESCE(old_parent,0) <> COALESCE(new_parent,0) THEN
      EXECUTE '
      -- prevent cycles in the tree
      UPDATE ' || TG_ARGV[0] || ' SET ' || TG_ARGV[2] || ' = $1.' || TG_ARGV[2]
        || ' WHERE id=$2.' || TG_ARGV[2] || ' AND EXISTS(SELECT 1 FROM '
        || TG_ARGV[1] || ' WHERE child_id=$2.' || TG_ARGV[2] || ' AND ancestor_id=$2.id);
      -- first remove edges between all old parents of node and its descendants
      DELETE FROM ' || TG_ARGV[1] || ' WHERE child_id IN
        (SELECT child_id FROM ' || TG_ARGV[1] || ' WHERE ancestor_id = $1.id)
        AND ancestor_id IN
        (SELECT ancestor_id FROM ' || TG_ARGV[1] || ' WHERE child_id = $1.id AND ancestor_id <> $1.id);
      -- then add edges for all new parents ...
      INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT child_id,ancestor_id,d_c+d_a FROM
        (SELECT child_id,depth AS d_c FROM ' || TG_ARGV[1] || ' WHERE ancestor_id=$2.id) AS child
        CROSS JOIN
        (SELECT ancestor_id,depth+1 AS d_a FROM ' || TG_ARGV[1] || ' WHERE child_id=$2.' 
        || TG_ARGV[2] || ') AS parent;' USING OLD, NEW;
    END IF;
  END IF;
  RETURN NULL;
END;
$_$;

फिर प्रत्येक टेबल के लिए जहां मेरे पास पदानुक्रम है, मैं एक ट्रिगर बनाता हूं

CREATE TRIGGER nomenclature_tree_tr AFTER INSERT OR UPDATE ON nomenclature FOR EACH ROW EXECUTE PROCEDURE nomen_tree('my_db.nomenclature', 'my_db.nom_helper', 'parent_id');

मौजूदा पदानुक्रम से बंद तालिका को पॉप्युलेट करने के लिए मैं इस संग्रहीत प्रक्रिया का उपयोग करता हूं:

CREATE FUNCTION rebuild_tree(tbl_base text, tbl_closure text, fld_parent text) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
    EXECUTE 'TRUNCATE ' || tbl_closure || ';
    INSERT INTO ' || tbl_closure || ' (child_id,ancestor_id,depth) 
        WITH RECURSIVE tree AS
      (
        SELECT id AS child_id,id AS ancestor_id,0 AS depth FROM ' || tbl_base || '
        UNION ALL 
        SELECT t.id,ancestor_id,depth+1 FROM ' || tbl_base || ' AS t
        JOIN tree ON child_id = ' || fld_parent || '
      )
      SELECT * FROM tree;';
END;
$$;

क्लोजर टेबल को 3 कॉलम - ANCESTOR_ID, DESCENDANT_ID, DEPTH के साथ परिभाषित किया गया है। यह संभव है (और मैं भी सलाह) एन्सेस्टर और डिस्काउंटेंट के लिए समान मूल्य के साथ रिकॉर्ड स्टोर करने के लिए, और DEPTH के लिए शून्य का मान। यह पदानुक्रम की पुनर्प्राप्ति के लिए प्रश्नों को सरल बना देगा। और वे वास्तव में बहुत सरल हैं:

-- get all descendants
SELECT tbl_orig.*,depth FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth <> 0;
-- get only direct descendants
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth = 1;
-- get all ancestors
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON ancestor_id = tbl_orig.id WHERE descendant_id = XXX AND depth <> 0;
-- find the deepest level of children
SELECT MAX(depth) FROM tbl_closure WHERE ancestor_id = XXX;




sql oracle duplicate-data