Counting how many fields are the same in a row - sql

I have data in a table organised as follows:
ID, name1, name2, name3, name4, name5, name6
Sample data
select ID, name1, name2, name3, name4, name5, name6
from datatable
123, bob, mark, jane, bob, jane, fred
124, mark, mark, mark, bob, bob, bob
and I need to end up with something like
123, bob, 2
123, mark, 1
123, jane, 2
123, fred, 1
124, mark, 3
124, bob, 3
Where the count is the number of times a name appears in the record. Is this possible?

The real reason you're having a problem here is because you have de-normalised data. Instead of 6 Name columns, you should have 1 column (called [Name]) and then another column to denote the "number" (ID?).
You can do this on the fly, however, using VALUES to Unpivot your data, and then perform a COUNT, but I strongly recommend you fix your table design in the long run:
SELECT DT.ID,
V.[Name],
COUNT(V.[Name]) AS Names
FROM dbo.DataTable DT
CROSS APPLY (VALUES(DT.name1),DT.(name2),(DT.name3),(DT.name4),(DT.name5),(DT.name6))V([Name])
GROUP BY DT.ID,
V.[Name];

Try this:
declare #tbl table (ID int, name1 varchar(10), name2 varchar(10), name3 varchar(10), name4 varchar(10), name5 varchar(10), name6 varchar(10))
insert into #tbl values
(123, 'bob', 'mark', 'jane', 'bob', 'jane', 'fred'),
(124, 'mark', 'mark', 'mark', 'bob', 'bob', 'bob')
select id, [name], count(*) cnt from (
select ID, name1 [name] from #tbl
union all
select ID, name2 from #tbl
union all
select ID, name3 from #tbl
union all
select ID, name4 from #tbl
union all
select ID, name5 from #tbl
union all
select ID, name6 from #tbl
) a group by id, [name]

Using a union approach:
WITH cte AS (
SELECT ID, name1 AS name FROM yourTable UNION ALL
SELECT ID, name2 FROM yourTable UNION ALL
SELECT ID, name3 FROM yourTable UNION ALL
SELECT ID, name4 FROM yourTable UNION ALL
SELECT ID, name5 FROM yourTable UNION ALL
SELECT ID, name6 FROM yourTable
)
SELECT
ID,
name,
COUNT(*) AS Count
FROM cte
GROUP BY
ID,
name
ORDER BY
ID,
name;
Demo

Related

sql using Aggregates using a combination of min(), count(), having clause

Trying to find code that will allow me to count first names by group, and then return the name with the lowest count.
Sample data:-
PersonGroup FirstName
------------------------
A Bob
A Mary
A Bob
A Bob
B Michelle
B Michelle
B Greg
B Greg
B Michelle
C Cindy
C Michelle
C Michelle
D Rod
D Rod
D Rod
D Rod
D Rod
D Mary
D Mary
D Mary
D Mary
D Mary
D Mary
Output required :
PersonGroup FirstName Count
--------------------------------
A Mary 1
B Greg 2
C Cindy 1
D Rod 5
First Name columns has the name that occurs the least within the group
Count column has the count of Name that occurs the least amount of times per group
this is my code so far, but every name is being returned,
select
PersonType,
FirstName,
count (firstName) as mycount
from
[Person].[Person]
group by
FirstName,
[PersonType]
having
count(firstName) = (select min(a.cnt)
from
(select count(firstname) as cnt
from [Person].[Person]
group by [FirstName]) as a)
order by
PersonType desc
you can use row_number()
select a.*
from (select PersonType,FirstName ,count (firstName) as mycount,
row_number() over (partition by PersonType order by count(*)) as rn
from [Person].[Person]
group by FirstName,[PersonType]
) a
where rn= 1;
use window function row_number()
with cte as
(
select 'A' as PersonGroup, 'Bob' as name
union all
select 'A', 'Mary'
union all
select 'A', 'Mary'
union all
select 'B', 'Michelle'
union all
select 'B', 'Greg'
union all
select 'B', 'Greg'
union all
select 'B', 'Michelle'
union all
select 'B', 'Michelle'
union all
select 'C', 'Michelle'
union all
select 'C', 'Michelle'
union all
select 'C', 'Cindy'
union all
select 'D', 'Rod'
union all
select 'D', 'Rod'
union all
select 'D', 'Rod'
union all
select 'D', 'Rod'
union all
select 'D', 'Rod'
union all
select 'D', 'Mary'
union all
select 'D', 'Mary'
union all
select 'D', 'Mary'
union all
select 'D', 'Mary'
union all
select 'D', 'Mary'
union all
select 'D', 'Mary'
)
, cte3 as (
select personGroup, name, COUNT(*) as cnt, row_number() over(partition by PersonGroup order by COUNT(*) ) rn from cte GROUP BY personGroup, name
) select PersonGroup,name,cnt from cte3 where rn=1
demo link

Generating string of numbers in random order

I need to generate a string of the numbers 1-3 with the numbers in random order for each row selected from a table.
I have tried the following, but am unable to get the random numbers to change for each row (they are the same across all rows).
SELECT name
, (SELECT LISTAGG( COLUMN_VALUE ) WITHIN GROUP ( ORDER BY dbms_random.value )
FROM TABLE( SYS.ODCIVARCHAR2LIST( '1', '2', '3' ) )
) AS q_order
FROM tableA
Desired Result:
NAME Q_ORDER
-------------------
Name1 123
Name2 312
Name3 213
What I actually get:
NAME Q_ORDER
-------------------
Name1 312
Name2 312
Name3 312
Version: Oracle 11.2.0
Something like this... (simple but efficient). The second column is a string; if you need it as a number, apply TO_NUMER() to it. Of course, the values in the second column will be DIFFERENT every time you run the query (the values ARE indeed random!)
with
tablea ( name ) as (
select 'Name1' from dual union all
select 'Name2' from dual union all
select 'Name3' from dual
)
select name,
case floor(dbms_random.value(0, 6))
when 0 then '123'
when 1 then '132'
when 2 then '213'
when 3 then '231'
when 4 then '312'
else '321' end as q_order
from tablea
;
NAME Q_ORDER
----- -------
Name1 123
Name2 312
Name3 213
Your approach will probably work with some tweaking. Oracle would appear to be optimizing away the fact that the code should run for each row.
One method is to include an outer reference to bypass this optimization. I think this is sufficient:
SELECT name,
(SELECT LISTAGG( COLUMN_VALUE ) WITHIN GROUP ( ORDER BY dbms_random.value )
FROM TABLE( SYS.ODCIVARCHAR2LIST( '1', '2', '3' ) )
WHERE a.name is not null
) AS q_order
FROM tableA a;

how to select specific number of column for specific number of ID?

Hi I have the following table
table_A
ID NAME PRICE DATE
123 JOHN 22 1/1/2010
234 KING 50 5/10/2009
345 JACK 400 30/11/210
Expected out put:
I want to pick first column for fist ID and second column for second ID and third column for third ID.
ID VALUES
123 JOHN
234 50
345 30/11/2010
My query:
select ID, NAME
from table_A
where ID = 123
union all
select ID, PRICE
from table_A
where ID = 234
union all
select ID, DATE
from table_A
where ID = 345;
Two reason that my query is not correct:
1) it don't union different data types
2) its difficult to type all ID and so, many unions
Need better query so, it automatically pick first loan for first column and second loan for second column...
This will work but you do have to convert all your data to the same format:
with test_data(ID1, NAME1, PRICE, DATE1)
as (
select 123, 'JOHN', 22, '1/1/2010' from dual union all
select 234, 'KING', 50, '5/10/2009' from dual union all
select 345, 'JACK', 400, '30/11/210' from dual
)
select ID1, DATA
FROM
(
select ID1, DATA, COL,
row_number() over (partition by ID1 order by id1) RN,
dense_rank() over (order by id1) DR
from (
select
cast(ID1 as varchar(10)) ID1,
cast(NAME1 as varchar(10)) NAME1,
cast(PRICE as varchar(10)) PRICE,
cast(DATE1 as varchar(10)) DATE1
FROM test_data
)
unpivot
(
DATA for COL in (NAME1, PRICE, DATE1)
)
)
where DR = RN
ID1 DATA
---------- ----------
123 JOHN
234 50
345 30/11/210
select
cast(ID as varchar(10)),
cast(NAME as varchar(10))
from table_A
where ID = 123
union all
select
cast(ID as varchar(10)),
cast(PRICE as varchar(10))
from table_A
where ID = 234
union all
select
cast(ID as varchar(10)),
cast(DATE as varchar(10))
from table_A
where ID = 345;

Find duplicates out of multiple columns

I have a tricky sql problem. Let me qive you an example
ID1 Name Name2 Name3 Name4
100 Albert Kevin Jon Alex
101 Albert Jon Kevin Alex
102 Albert Georg Alex Babera
103 Albert Stefany
Lets say ID1 gives me a project ID and Name is the main person (Albert). Name2-4 are subgroups of people who worked with Albert. Now I want to count matches between this subgroups. First I want to know exact matches. For example between 100 and 101.
Second is it possible to count how many names matches? Like one match between 101 and 100.
Thanks in advance
I know it is long and not bulletproof but it kind of does the job.
WITH source_t AS
(
SELECT 100 id, 'Albert' name, 'Kevin' name2, 'Jon' name3, 'Alex' name4 FROM DUAL UNION ALL
SELECT 101, 'Albert', 'Jon', 'Kevin', 'Alex' FROM DUAL UNION ALL
SELECT 102, 'Albert', 'Georg', 'Alex', 'Babera' FROM DUAL UNION ALL
SELECT 103, 'Albert', 'Stefany', NULL, NULL FROM DUAL
)
, tab_1 AS
(
SELECT id, name, name2 FROM source_t UNION ALL
SELECT id, name, name3 FROM source_t UNION ALL
SELECT id, name, name4 FROM source_t
)
, tab_2 AS
(
SELECT id
, name
, name2
, ROW_NUMBER() OVER (PARTITION BY id, name ORDER BY name2) AS r_number
FROM tab_1
)
, tab_3 AS
(
SELECT id
, name
, MAX(CASE WHEN r_number = 1 THEN name2 END) AS name2
, MAX(CASE WHEN r_number = 2 THEN name2 END) AS name3
, MAX(CASE WHEN r_number = 3 THEN name2 END) AS name4
FROM tab_2
GROUP BY
id
, name
)
SELECT tab_3.id
, tab_3.name
, tab_3.name2
, tab_3.name3
, tab_3.name4
, tab_4.n_count
FROM tab_3
LEFT JOIN
(
SELECT name
, name2
, name3
, name4
, COUNT(1) AS n_count
FROM tab_3
GROUP BY
name
, name2
, name3
, name4
) tab_4
ON tab_3.name = tab_4.name
and NVL(tab_3.name2, 'NULL') = NVL(tab_4.name2, 'NULL')
and NVL(tab_3.name3, 'NULL') = NVL(tab_4.name3, 'NULL')
and NVL(tab_3.name4, 'NULL') = NVL(tab_4.name4, 'NULL')
;
/*
102 Albert Alex Babera Georg 1
103 Albert Stefany NULL NULL 1
101 Albert Alex Jon Kevin 2
100 Albert Alex Jon Kevin 2
*/

Query to get only the duplicate data

I have a table with data
ID Name
1 John
2 Robert
3 John
4 Sam
5 Jack
6 Sam
Now i want ony the the duplicate names ony through query
ie..,
Name
John
Sam
SELECT Name
FROM YourTable
GROUP BY Name
HAVING COUNT(*) > 1
CREATE TABLE MyTable (
ID int
, Name nvarchar(50)
)
INSERT MyTable VALUES ( 1, 'John' )
INSERT MyTable VALUES ( 2, 'Robert' )
INSERT MyTable VALUES ( 3, 'John' )
INSERT MyTable VALUES ( 4, 'Sam' )
INSERT MyTable VALUES ( 5, 'Jack' )
INSERT MyTable VALUES ( 6, 'Sam' )
SELECT
Name
FROM
MyTable
GROUP BY
Name
HAVING
COUNT(*) > 1
DROP TABLE MyTable
Results:
Name
--------------------------------------------------
John
Sam
with temp as (
select Name, count(Name) as countOfNames
from myTable
group by Name
)
select Name from temp
where countOfNames > 1
select columnname,count(column name) from tablename group by column name having count(*)>1