SQL: How compare cells from different tables? - sql

I have two tables - band and band2. Band:
and band2:
The columns are equals. I'm using Access 2010. I want to SELECT rows WHERE band.Kampas<>band2.Kampas, but there isn't primary key so I can't use JOIN operation.
Maybe someone has an idea?
The answer:
Only in these rows band.Kampas<>band2.Kampas.
Thanks in advance.

SELECT b2.*
FROM band2 b2
WHERE b2.kampas NOT IN (SELECT b1.kampas
FROM band b1
WHERE b1.kampas IS NOT NULL)
AND b2.kampas IS NOT NULL

If I understand you correctly this is what you want:
Select * from band where kampas not in (select kampas from band2)
union
Select * from band2 where kampas not in (select kampas from band)
EDIT. Ok, might be that not in doesn't work in Access. It looks like this could work, though:
Select * from band2 where not exists (select * from band where band.kampas = band2.kampas)
This find a selection in the inner select where kampas's match and we want to pick those band2 lines that returns an empty selection in the inner select.
If you want to do this two-way (i.e. also find from band) just use union like I did in the first attempt.

How about this:
select *
from Band as B1
inner join Band2 as B2
on B1.Stotis = B2.Stotis
where B1.Kampas <> B2.Kampas

Related

How to get different data from two different tables in SQL query?

I have two table named Soft and Web, table containing multiple data in that which data is different that data I want. For Ex :
In soft table containing 5 data i.e.
Also in Web table containing 5 data i.e.
Now I want output i.e.
I have done query but unfortunately didnt succed, lets see my query i.e.
SELECT DISTINCT soft.GSTNo AS SoftGST
,web.GSTNo AS WebGST
,soft.InvoiceNumber AS SoftInvoice
,web.InvoiceNumber AS WebInvoice
,soft.Rate AS SoftRate
,web.Rate AS WebRate
FROM soft
LEFT OUTER JOIN web ON web.GstNo = soft.GSTNo
AND web.InvoiceNumber = soft.invoicenumber
AND web.rate = soft.rate
Also I apply inner join bt same thing didnt work.
You can achieve this by
;WITH cte_soft AS
(SELECT * FROM soft
EXCEPT
SELECT * FROM web)
,cte_web AS
(SELECT * FROM web
EXCEPT
SELECT * FROM soft)
SELECT *
FROM
(SELECT gst softgst, NULL webgst, invoice softinvoice, NULL webinvoice, rate softrate, NULL webrate
FROM cte_soft
UNION ALL
SELECT NULL, gst, NULL, invoice, NULL , rate
FROM cte_web) tbl
ORDER BY coalesce(softgst, webgst),coalesce(softinvoice,webinvoice)
Fiddle
You can use full join:
SELECT s.gst as softgst, w.gst as webgst,
s.invoice as softinvoice, w.invoice as webinvoice,
s.rate as softrate, w.rate as webrate
FROM soft s FULL JOIN
web w
ON s.gst = w.gst AND s.invoice = w.invoice AND s.rate = w.rate
WHERE s.gst IS NULL OR w.gst IS NULL
ORDER BY COALESCE(s.gst, w.gst), COALESCE(s.invoice, w.invoice);
No subqueries are CTEs are needed. This is really just a slight variant of your query.

Change existing sql to left join only on first match

Adding back some original info for historical purposes as I thought simplifying would help but it didn't. We have this stored procedure, in this part it is selecting records from table A (calldetail_reporting_agents) and doing a left join on table B (Intx_Participant). Apparently there are duplicate rows in table B being pulled that we DON'T want. Is there any easy way to change this up to only pick the first match on table B? Or will I need to rewrite the whole thing?
SELECT 'Agent Calls' AS CallType,
CallDate,
CallTime,
RemoteNumber,
DialedNumber,
RemoteName,
LocalUserId,
CallDurationSeconds,
Answered,
AnswerSpeed,
InvalidCall,
Intx_Participant.Duration
FROM calldetail_reporting_agents
LEFT JOIN Intx_Participant ON calldetail_reporting_agents.CallID = Intx_Participant.CallIDKey
WHERE DialedNumber IN ( SELECT DialedNumber
FROM #DialedNumbers )
AND ConnectedDate BETWEEN #LocStartDate AND #LocEndDate
AND (#LocQueue IS NULL OR AssignedWorkGroup = #LocQueue)
Simpler version: how to change below to select only first matching row from table B:
SELECT columnA, columnB FROM TableA LEFT JOIN TableB ON someColumn
I changed to this per the first answer and all data seems to look exactly as expected now. Thank you to everyone for the quick and attentive help.
SELECT 'Agent Calls' AS CallType,
CallDate,
CallTime,
RemoteNumber,
DialedNumber,
RemoteName,
LocalUserId,
CallDurationSeconds,
Answered,
AnswerSpeed,
InvalidCall,
Intx_Participant.Duration
FROM calldetail_reporting_agents
OUTER APPLY (SELECT TOP 1
*
FROM Intx_Participant ip
WHERE calldetail_reporting_agents.CallID = ip.CallIDKey
AND calldetail_reporting_agents.RemoteNumber = ip.ConnValue
AND ip.HowEnded = '9'
AND ip.Recorded = '0'
AND ip.Duration > 0
AND ip.Role = '1') Intx_Participant
WHERE DialedNumber IN ( SELECT DialedNumber
FROM #DialedNumbers )
AND ConnectedDate BETWEEN #LocStartDate AND #LocEndDate
AND (#LocQueue IS NULL OR AssignedWorkGroup = #LocQueue)
You can try to OUTER APPLY a subquery getting only one matching row.
...
FROM calldetail_reporting_agents
OUTER APPLY (SELECT TOP 1
*
FROM intx_Participant ip
WHERE ip.callidkey = calldetail_reporting_agents.callid) intx_participant
WHERE ...
You should add an ORDER BY in the subquery. Otherwise it isn't deterministic which row is taken as the first. Or maybe that's not an issue.

SQL give cells the same value if cell in another column is partly similar

I'm pretty new to SQL. And I'm trying the following.
I have the following table1 with Columns group and description.
Table1 Example
I want to check if the cell values are partly the same. Like in this case Group101 and Group101D1. Now I want to take the description from the value with D1 and put it in the description column of the one without D1.
And do this for all the cells where the Group value is partly the same.
SELECT [Group]
,[Description]
FROM [Table1]
update [Table1]
set Description = (Select [Description] from [Table1] where [Group] like '%Group101D1%')
where Address like '%Group1%'
This is how far I came. I can make it work for one but have to split it up and make it work for all of them.
Try this query:
WITH cte AS (
SELECT t1.Description AS desc_dest, t2.Description AS desc_src
FROM yourTable t1
INNER JOIN yourTable t2
ON t2.[Group] LIKE t1.[Group] + '[A-Z]%' AND LEN(t1.[Group]) <= 9
)
UPDATE cte
SET desc_dest = desc_src;
Demo
If you simply want to get consistency between all descriptions that only differ in the last two characters, the following should to the trick:
WITH CTE AS
(
SELECT
a.Description
, b.Description AS Descriptionb
FROM
TABLE1 a
JOIN [Table1] b ON LEFT(a.[Group], LEN(a.[Group]) - 2) = b.[Group]
)
update CTE
set Description = Descriptionb
The self-join establishes that we look for all descriptions where the last 2 characters from set a (Group101D1) are removed so we end up with Group101. We then look for a match in set b. If we find it, we set the values of b to match the values in a.
This means the description of Group101D1 will be set to Group101, as would Group101XX. It also should allow for handling of Group1010404D1 to change Group1010404.
Edit: Switched the UPDATE around. I read things wrong and it would have updated the wrong values.
Edit2: As Tim said, my join was wrong. The above should work, though.
My solution is the following:
SELECT [Table1].[Description]
, [Table2].[Description]
,[Table1].[Group]
,[Table2].[Group]
--update [Table1] set [Table1].[Description] = [Table2].[Description]
FROM [BVCIOList_DOW].[dbo].[Table] Table1
INNER JOIN [BVCIOList_DOW].[dbo].[Table] Table2
ON [Table2].[Group] = [Table1].[Group] + 'D1'

I need to make 2 different AVG colums, but can't seem to get this to work

SELECT AVG(goals1) FROM matches
WHERE cid='1'
(SELECT AVG(goals2) FROM matches
WHERE cid='2')
;
SELECT AVG(goals1) AvgCid1, (SELECT AVG(goals2) FROM matches WHERE cid='2') AvgCid2
FROM matches
WHERE cid='1'
Add UNION between the statements like this:
SELECT AVG(goals1) FROM matches
WHERE cid='1'
UNION
SELECT AVG(goals2) FROM matches
WHERE cid='2'
You may need to name the columns as well.
How about this?
SELECT * FROM
(SELECT AVG(goals1) AS goals1 FROM matches WHERE cid='1') t1
full outer join
(SELECT AVG(goals2) AS goals2 FROM matches WHERE cid='2') t2
ON t1.goals1 <> t2.goals2;

Concatenating two columns in Oracle giving performance issue

I have a select query where I am doing inner joins and in AND clause I am checking like this
AND UPPER (b.a1||b.a2) IN
(
select a.a1||a.a2
from a
where a.a3 =
(
select UPPER(decode('609',null,c.c1,'609'))
from dual
)
)
but so because of || opertaor it is taking more than 2 minutes. Can we have any other solution to this?
How about using EXISTS clause?
AND EXISTS (
SELECT
1
FROM
a
WHERE
a.a3 = (SELECT UPPER(DECODE('609',c.c1,'609')) FROM dual) -- this condition is pretty odd
AND a.a1 = UPPER(b.a1)
AND a.a2 = UPPER(b.a2)
)
Adding Function Based Indexes on UPPER(b.a1) AND UPPER(b.a2) may help as well.
Speaking of that odd condition: (SELECT UPPER(DECODE('609',c.c1,'609')) FROM dual):
Why do you perform a SELECT from dual there?
What you check is - if '609' equals c.c1 ('609') then a.a3 must equal '609', in any other case your SELECT returns NULL, thus no value from table a is returned. So you can just change the entire condition to a.a3 = '609'.
Try with a JOIN
SELECT *
FROM b
JOIN ( select UPPER(a.a1), UPPER(a.a2)
from a
where a.a3 = (select UPPER(decode('609',c.c1,'609')) from dual)
) a
ON UPPER(b.b1) = a.a1
AND UPPER(b.b2) = a.a2
But the problem is when you do UPPER(b.b1) or b1||b2 you cant use the index anymore.
You may need a function index
You don't need to concatenate. In fact: concatenating the values is a bug waiting to happen: consider the the values foob and ar in table b and foo and bar in a - the concatenation treats those as the same tuple although they are not.
You also don't need the select from dual for a constant:
AND (UPPER (b.a1), upper(b.a2)) IN
(
select a.a1. a.a2
from a
where a.a3 = UPPER(decode('609',null,c.c1,'609'))
)
An index on b(a1,a2) can't be used for this, but you can create an index on b (UPPER (b.a1), upper(b.a2)) which would be used.