How to get same results without using distinct in query - sql

I have a table with data like so:
[ID, Name]
1, Bob
1, Joe
1, Joe
1, Bob
I want to retrieve a list of records showing the relationship between the records with the same ID.
For instance, I want the following result set from my query:
Bob, Joe
Joe, Bob
Bob, Bob
Joe, Joe
This shows me the "from" and "to" for every item in the table.
I can get this result by using the following query:
SELECT DISTINCT [NAME]
FROM TABLE A
INNER JOIN TABLE B ON A.ID = B.ID
Is there anyway for me to achieve the same result set without the use of the "distinct" in the select statement? If I don't include the distinct, I get back 16 records, not 4.

The reason you get duplicate rows without DISTINCT is because every row of ID = x will be joined with every other row with ID = x. Since the original table has (1, "Bob") twice, both of those will be joined to every row in the other table with ID = 1.
Removing duplicates before doing a join will do two things: decrease the time to run the query, and prevent duplicate rows from showing up in the result.
Something like (using MySQL version of SQL):
SELECT L.NAME, R.NAME
FROM (SELECT DISTINCT ID, NAME FROM A) AS L
INNER JOIN (SELECT DISTINCT ID, NAME FROM B) AS R
ON L.ID = R.ID
Edit: is B an alias for table A?

In SQL and MY SQL
SELECT COLUMN_NAME FROM TABLE_NAME group by COLUMN_NAME

Have you tried using a group by clause?
select name
from table a
inner join table b
on a.id=b.id
group by name
That should get you the same thing as your distinct query above. As for the result set that you want, a simple self join should do it:
select name1,name2
from(
select id,name as name1
from table
group by 1,2
)a
join(
select id,name as name2
from table
group by 1,2
)b
using(id)

Eliminating duplicate values with union without using distinct
Declare #TableWithDuplicateValue Table(Name Varchar(255))
Insert Into #TableWithDuplicateValue Values('Cat'),('Dog'),('Cat'),('Dog'),('Lion')
Select Name From #TableWithDuplicateValue
union
select null where 1=0
Go
Output
---------
Cat
Dog
Lion
For more alternate kindly visit my blog
http://www.w3hattrick.com/2016/05/getting-distinct-rows-or-value-using.html

Related

oracle minus in select statement

I have two Tables. A & B
ID Name
1 A
2 B
3 C
4 D
and
ID Sal
1 400
2 300
3 500
Now I need to fetch the record (both ID, Name) from first table, those sal is not assigned in second table. Using sub query I got this. But i need to solve it without using sub query.
So I tried with minus operator. But I am getting full first table as it is.
select id,name from A
minus
select id,to_char(null) from B;
What am I doing wrong?
But without Using Sub Query i need to Solve.
Use this using CTE:
with tbl(id) as ( select id from B)
select id,name
from A
inner join tbl b
on a.id <> b.id
You can use the minus inside with clause
with ids as (
select id
from A
minus
select id
from B
) select A.id ,A.name
from A join ids on ids.userid=A.userid;

insert into with two selects and compare

It looks stupid in this example but here is what I want to do:
Table_a:
id fk_b_id full_name
1 [I want '10' here] [I want 'John, Doe' here]
Table_b:
id first_name
10 John
Table_c:
id full_name date
20 John, Doe 2020-01-01
I get all the full names that is not already in c and meets the criteria like this:
select distinct full_name
from Table_c
where full_name not in (
select full_name
from Table_a ) and date > GETDATE()
The result from the query should be inserted into Table_a together with Table_b's id (fk_b_id). So I need a compare between part of Table_a's full_name and Table_b's first_name to get the correct fk. I can do the compare like this:
where Table_b.first_name = LTRIM(RTRIM(RIGHT(Table_c.full_name, CHARINDEX(',', REVERSE(Table_c.full_name))-1 )))
Can I insert all the full names from table c (that meets the criteria) and the fk from table b (where their first names match) into table a in one query?
Sure, just use your condition to JOIN between tables B and C
INSERT INTO Table_a (fk_b_id, full_name)
SELECT DISTINCT b.id, c.full_name
FROM Table_c c
INNER JOIN Table_b b ON b.first_name = LTRIM(RTRIM(RIGHT(c.full_name, CHARINDEX(',', REVERSE(c.full_name))-1 )))
WHERE c.full_name not in (
select a.full_name
from Table_a a ) and c.date > GETDATE()
EDIT:
Also note, that if your table_a.full_name column can have NULL values, NOT IN sub-query will fail to give you expected results. I suggest rewriting it to use NOT EXISTS
WHERE NOT EXISTS
(SELECT * FROM Table_a WHERE Table_a.Full_Name = Table_c.FUll_Name )

SQL query to exclude original rows which there is a copy of them

In MyTable I have a column named CopyOf which holds the ID of other original row from the same table (MyTable). I want to select all rows except the original rows which there is a Copy of them. But I don't know how to manage conditions both in "ON" and "WHERE"
Select * from MyTable a left join MyTable b on ?????? where ???????
Sample data:
ID | CopyOf
1 |
2 |
3 | 1
I want just to select rows 2 and 3 because there is a copy of 1.
If you want to do this in a join and where then use a query like the one below;
SELECT
a.*
FROM MyTable a
LEFT JOIN MyTable b
ON a.ID = b.CopyOf
WHERE b.CopyOf IS NULL
This will join the table back to itself and then ignore any that are a copy of something in the same table.
Another option you appear to have is that you can just look for everything that isn't a copy of something else, like this;
SELECT
a.*
FROM MyTable a
WHERE a.CopyOf IS NULL
Another option is this;
SELECT
a.*
FROM MyTable a
WHERE a.ID NOT IN (SELECT CopyOf FROM MyTable)
Which will exclude any ID's completely that have a record in the CopyOf field. This final one will return only ID's that don't have any copies at all. Re-reading your question, I think this final query is the one you're after.
I assumed you want to show all data that is not available from table2. Here's my solution
Use NOT IN in your WHERE Clause.
Like this:
SELECT * FROM MyTable
WHERE ID NOT IN (SELECT DISTINCT ID FROM MyTable2)

Query to find field duplicate between 9 tables

I have 9 tables each with value like
Level_1_tab
Code Name
ae1 hdgdgd
ae2 dhdh
level_2_tab
code Name
2 jfjfjf
3 fkfjfjf
similarly level_3_tab , level_4_tab, level_5 table so on and so forth till level_9_tab.
I am inserting the code column into a new table and checking for duplicates.
SELECT
code, name, COUNT(*)
FROM
new_table
GROUP BY
code, name
HAVING
COUNT(*) > 1;
Can i write a query and compare the code column of these 9 tables and check for duplicates ? that all the rows with duplicate code values should be retrieved
You can do a union all of the 9 tables and run your same query on that.
select code, name, count(*) from
(select code, name from table 1 union all
select code, name from table 2 union all
select code, name from table 3 union all
select code, name from table 4 union all
.....)
group by code, name
having count(*) > 1;
Everyone's suggestion of union all is great to build your initial table to look for duplicates in. But you say you already have a temp table with all of the values from the 9 tables which is perfect and another great way of doing it if your dataset isn't huge.
The only step your missing from your description to get the actually duplicate rows is to use your duplicate query above to re-query your temp table and return the rows you want. A great way of doing this is through common table expressions which basically allows you to build a query on top of your other query without another temp table. So use a cte and join back to your temp table.
;WITH CommonTableExpression AS (
SELECT
code, name, COUNT(*)
FROM
new_table
GROUP BY
code, name
HAVING
COUNT(*) > 1;
)
SELECT t.*
FROM
new_table t
INNER JOIN CommonTableExpression c
ON t.code = c.code
AND t.name = c.name
If you want to do it to each of the 9 tables independently rather than to your temp table. Place the duplicates into another temp table and join on it.
SELECT
code, name, COUNT(*)
INTO #Duplicates
FROM
new_table
GROUP BY
code, name
HAVING
COUNT(*) > 1
SELECT
l.*
FROM
leve_1_tab l
INNER JOIN #Duplicates d
ON l.Code = d.Code
AND l.name = d.name
Seeing everyone loves union all here is a way to do it with out temp tables and lots of union all s I wonder which would be a more optimized query though.
;WITH cteAllCodeValues AS (
select code, name from table 1 union all
select code, name from table 2 union all
select code, name from table 3 union all
select code, name from table 4 union all
--.....)
)
, cteDuplicates AS (
SELECT code, name, RecordCount = COUNT(*)
FROM
cteAllCodeValues
GROUP BY
code, name
)
SELECT c.*
FROM
cteDuplicates d
INNER JOIN cteAllCodeValues c
ON d.code = c.code
AND d.name = c.name

Efficiently Include Column not in Group By of SQL Query

Given
Table A
Id INTEGER
Name VARCHAR(50)
Table B
Id INTEGER
FkId INTEGER ; Foreign key to Table A
I wish to count the occurrances of each FkId value:
SELECT FkId, COUNT(FkId)
FROM B
GROUP BY FkId
Now I simply want to also output the Name from Table A.
This will not work:
SELECT FkId, COUNT(FkId), a.Name
FROM B b
INNER JOIN A a ON a.Id=b.FkId
GROUP BY FkId
because a.Name is not contained in the GROUP BY clause (produces is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause error).
The point is to move from output like this
FkId Count
1 42
2 25
to output like this
FkId Count Name
1 42 Ronald
2 22 John
There are quite a few matches on SO for that error message, but some e.g. https://stackoverflow.com/a/6456944/141172 have comments like "will generate 3 scans on the table, rather than 1, so won't scale".
How can I efficiently include a field from the joined Table B (which has a 1:1 relationship to FkId) in the query output?
You can try something like this:
;WITH GroupedData AS
(
SELECT FkId, COUNT(FkId) As FkCount
FROM B
GROUP BY FkId
)
SELECT gd.*, a.Name
FROM GroupedData gd
INNER JOIN dbo.A ON gd.FkId = A.FkId
Create a CTE (Common Table Expression) to handle the grouping/counting on your Table B, and then join that result (one row per FkId) to Table A and grab some more columns from Table A into your final result set.
Did you try adding the field to the group by?
SELECT FkId, COUNT(FkId), a.Name
FROM B b
INNER JOIN A a ON a.Id=b.FkId
GROUP BY FkId,a.Name
select t3.Name, t3.FkId, t3.countedFkId from (a t1
join (select t2.FkId, count(FkId) as countedFkId from b t2 group by t2.FkId)
on t1.Id = t2.FkId) t3;