sqlite extra column with 1 and 0 if record exists in related table or not - sql

I am not so good at SQL, so I have the following tables
Stuff
and
Specialty
Let's say, the worker with name 'Bob' has two specialties. How could I get the specialty table with an extra column (let's say count) which has 1 if the record exists in Stuff and 0 otherwise.
I would like to ask if there is any way to cast a query
that returns a result for Bob as shown below?
Any suggestions would be very helpful. Thank you in advance.
(I am not sure about the title. Please do suggest if you have a better idea!)

I would be inclined to do this with a case and exists:
select sp.*,
(case when exists (select 1
from stuff s
where s.surname = 'Bob' and
s.speciality_code = sp.speciality_code
)
then 1 else 0
end) as BobHas
from specialty sp;

Use Left Outer join with Null check. Try this.
SELECT sp.specialitycode,
sp.description,
CASE
WHEN st.specialitycode IS NULL THEN 0
ELSE 1
END AS count
FROM speciality sp
LEFT OUTER JOIN (SELECT specialitycode
FROM stuff
WHERE surname = 'Bob') st
ON sp.specialitycode = st.specialitycode

Related

Join Tables to return 1 or 0 based on multiple conditions

I am working on a project management website and have been asked for a new feature in a review meeting section.
A meeting is held to determine whether to proceed to the next phase, and I need to maintain a list of who attended each phase review meeting. I need to write an SQL query to return all people, with an additional column that states they have already been added before.
There are two tables involved to get my desired result, with the relevant columns listed below:
Name: PersonList
ID | Name | Division
Name: reviewParticipants
ProjectID | PersonID | GateID
The query I am looking for is something that returns all people in PersonList, with an additional "hasAttended" bit that is TRUE if reviewParticipants.ProjectID = 5 AND reviewParticpants.CurrentPhase = 'G0' ELSE FALSE.
PersonName | PersonID | hasAttended
Mr Smith | 1 | 1
Mr Jones | 2 | 0
I am not sure how to structure such a query with multiple conditions in a (left?) join, that would return as a different column name and data type, so I would appreciate if anybody can point me in the right direction?
With the result of this query I am going to add a series of checkboxes, and use this additional bit to mark it checked, or not, for page refreshes.
You can use LEFT JOIN as well:
SELECT DISTINCT p.*
,CASE WHEN rp.id IS NOT NULL THEN 1 ELSE 0 END AS hasAttended
FROM personlist p
LEFT JOIN reviewParticipants rp ON rp.personid = p.id
AND rp.projectid = 5
AND rp.currentphase = 'GO'
I agree with Gordon Linoff: I would prefer an int or tinyint over a bit value,
You can use exists to see if there is a matching row.
select p.*,
(case when exists (select 1
from reviewParticipants rp
where rp.personid = p.id and
rp.projectid = 5 and
rp.currentphase = 'GO'
)
then 1 else 0 end)
from personlist p;
I see no reason to prefer a bit over an integer, but you can return a bit if you really prefer.
This will do :
select a.* from PersonList a where a.hasAttended=1 and
a.Id in (select b.PersonId from reviewParticipants b
where b.ProjectID =5 and exists (
select 1 from reviewParticipants c where c.CurrentPhase = 'G0'and
c.Project =b.projectId
)
)

SQL query having CASE WHEN EXISTS statement

I trying to create a SQL query with a CASE WHEN EXISTS clause in SQL Server. I assume I am doing something wrong as when I run the SELECT * FROM [Christmas_Sale] it takes forever for SQL to load the code.
CREATE VIEW [Christmas_Sale]
AS
SELECT
C.*,
CASE
WHEN EXISTS (SELECT S.Sale_Date
FROM [Christmas_Sale] s
WHERE C.ID = S.ID)
THEN 0
ELSE 1
END AS ChristmasSale
FROM
[Customer_Detail] C ;
I'm trying to write a sub select which I need to return a 1 if Sale_Date= 1 and 0 for anything else.
The syntax of your query looks ok. But since your stated:
I'm trying to write a sub select which I need to return a 1 if Sale_Date= 1 and 0 for anything else.
... Then you could rephrase your query by adding one more condition in the WHERE clause of the subquery:
CREATE VIEW [Christmas_Sale]AS
SELECT
C.*,
CASE WHEN EXISTS (
SELECT 1
FROM [Christmas_Sale] s
WHERE C.ID = S.ID and S.Sale_Date = 1
) THEN 0 ELSE 1 END AS ChristmasSale
FROM [Customer_Detail] C ;
If a record exists in [Christmas_Sale] with the corresponding ID and Sale_Date = 1, then ChristmasSale will have value 1, else it will display 0.
This query looks correct:
CREATE VIEW [Christmas_Sale] AS
SELECT C.*,
(CASE WHEN EXISTS (SELECT 1
FROM [Christmas_Sale] s
WHERE C.ID = S.ID
)
THEN 0 ELSE 1
END) AS ChristmasSale
FROM [Customer_Detail] C ;
If performance is an issue, you want an index on Christmas_Sale(ID).
Note that the SELECT S.Sale_Date in the subquery is meaningless, because EXISTS checks for rows not columns. Hence, I replaced it with the simpler 1.

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.

Selecting different columns from databases

Hello I have two databases and each has the same tables. For example I have table called world and it has 4 columns: pkey1, pkey2,companyid, company_name
I made a query which searches for rows which have the same pkey1 and pkey2 but one or many of their other property is different in the 2 tables. My question is how can I see only the different properties?
Here is my query it selects the rows which have the same pkey1 and pkey2 how can I upgrade it to see the columns where there is difference in both databases and of course if there is no difference the result of the query should return NULL in the column here is an example what I want to achieve:
in first database (1,1,345,'Ron'), second database (1,1,377,'Ron') the result should be (1,1,345,null)
Basically to reference data in a different database, you'll need a database link, since you are using PostgreSQL, this documentation should help;
https://www.postgresql.org/docs/current/static/dblink.html
You'll need to use this command to create the link (in this case with a name);
SELECT dblink_connect('CONNECTIONNAME', 'REMOTEDBCONNECTIONSTRING');
Then you can use this new connection via a select query;
SELECT *
FROM dblink('CONNECTIONNAME','SELECT * FROM foo') AS t(a int, b text, c text[]);
And replace 'foo' with your 'world' table name, then change the AS into the variables that relate to pkey1, pkey2,companyid, company_name etc.
If your databases are linked, you can join both tables and with "case" statement check if the value has changed:
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from db1.dbo.world a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2
If you want to omit rows with no difference you can use "except":
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from (
select pkey1, pkey2, companyid, company_name
from db1.dbo.world
except
select pkey1, pkey2, companyid, company_name
from db2.dbo.world) a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2

SQL Having Clause

I'm trying to get a stored procedure to work using the following syntax:
select count(sl.Item_Number)
as NumOccurrences
from spv3SalesDocument as sd
left outer join spv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type and
sd.Sales_Doc_Num = sl.Sales_Doc_Num
where
sd.Sales_Doc_Type='ORDER' and
sd.Sales_Doc_Num='OREQP0000170' and
sl.Item_Number = 'MCN-USF'
group by
sl.Item_Number
having count (distinct sl.Item_Number) = 0
In this particular case when the criteria is not met the query returns no records and the 'count' is just blank. I need a 0 returned so that I can apply a condition instead of just nothing.
I'm guessing it is a fairly simple fix but beyond my simple brain capacity.
Any help is greatly appreciated.
Wally
First, having a specific where clause on sl defeats the purpose of the left outer join -- it bascially turns it into an inner join.
It sounds like you are trying to return 0 if there are no matches. I'm a T-SQL programmer, so I don't know if this will be meaningful in other flavors... and I don't know enough about the context for this query, but it sounds like you are trying to use this query for branching in an IF statement... perhaps this will help you on your way, even if it is not quite what you're looking for...
IF NOT EXISTS (SELECT 1 FROM spv3SalesDocument as sd
INNER JOINs pv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type
and sd.Sales_Doc_Num = sl.Sales_Doc_Num
WHERE sd.Sales_Doc_Type='ORDER'
and sd.Sales_Doc_Num='OREQP0000170'
and sl.Item_Number = 'MCN-USF')
BEGIN
-- Do something...
END
I didn't test these but off the top of my head give them a try:
select ISNULL(count(sl.Item_Number), 0) as NumOccurrences
If that one doesn't work, try this one:
select
CASE count(sl.Item_Number)
WHEN NULL THEN 0
WHEN '' THEN 0
ELSE count(sl.Item_Number)
END as NumOccurrences
This combination of group by and having looks pretty suspicious:
group by sl.Item_Number
having count (distinct sl.Item_Number) = 0
I'd expect this having condition to approve only groups were Item_Number is null.
To always return a row, use a union. For example:
select name, count(*) as CustomerCount
from customers
group by
name
having count(*) > 1
union all
select 'No one found!', 0
where not exists
(
select *
from customers
group by
name
having count(*) > 1
)