order by first occurence of returned results - sql

I have two tables and want to get technology_tag from table b based on reference id from table a:
select b.dbid, b.technology_tag
from tblConnect a, tblSites b
where a.Site_DBID = 2
and a.Related_Site_DBID = 1
and (b.dbid = a.bsc_tag_dbid or b.dbid = a.related_bsc_dbid or b.dbid = a.related_msc_dbid)
What I want to have here is to order the returned rows based on first occurrence (in where clause)
1st- b.dbid = a.bsc_tag_dbid
2cnd- b.dbid = a.related_bsc_dbid
3rd- b.dbid = a.related_msc_dbid
Does anyone has a clue how to do that?

First, you should switch to using actual JOIN clauses when performing joins. That said, this ORDER BY clause should do what you want:
SELECT
B.dbid,
B.technology_tag
FROM tblConnect A
INNER JOIN tblSites B ON
B.dbid IN (A.bsc_tag_dbid, A.related_bsc_dbid, A.related_msc_dbid)
WHERE
A.Site_DBID = 2 AND
A.Related_Site_DBID = 1
ORDER BY
CASE
WHEN B.dbid = A.bsc_tag_dbid THEN 1
WHEN B.dbid = A.related_bsc_dbid THEN 2
WHEN B.dbid = A.related_msc_dbid THEN 3
ELSE 4 -- Not really necessary, but I always use an ELSE when I use CASE
END

Related

how do I loop through a set of records

how do I loop through a set of records from a select?
Here is my stored procedure query:
ALTER PROCEDURE [dbo].[procedure_rastavljanjeOtpremnica] (#radniNalogID INT) AS
DECLARE #bool BIT = 0
IF(#bool = 'FALSE')
BEGIN
SELECT ROW_NUMBER() OVER(ORDER BY S.PuniNaziv) AS num_row, S.PuniNaziv, a.KolicinaMjeracaIElektronike FROM ArtikliUslugeNaloga a
INNER JOIN SifreArtikala S ON S.Id = a.Artikal1Id
INNER JOIN UslugeNaloga ON UslugeNaloga.Id = a.UslugeNalogaId
WHERE a.RobaSkart = #bool AND UslugeNaloga.RadniNalogID = #radniNalogID
END
The result is:
now_row PuniNaziv Kolicina
1 Komunik internet jed s ugrađ WIFi sensoNET 3
2 Ventil tahret DN15 (1/2") 5
3 Vodokotlić Geberit 1
So what I need to do is to add another column that will print KOM for every row,
This is the result that I am looking for:
now_row PuniNaziv Kolicina Jedinia mjere
1 Komunik internet jed s ugrađ WIFi sensoNET 3 Kom
2 Ventil tahret DN15 (1/2") 5 Kom
3 Vodokotlić Geberit 1 Kom
Can anyone give me idea how to do this
There is no need to "loop". Just add the column to your query:
SELECT ROW_NUMBER() OVER (ORDER BY S.PuniNaziv) AS num_row,
S.PuniNaziv, a.KolicinaMjeracaIElektronike,
'Kom' as Jedinia_mjere
FROM ArtikliUslugeNaloga a JOIN
SifreArtikala S
ON S.Id = a.Artikal1Id JOIN
UslugeNaloga
ON UslugeNaloga.Id = a.UslugeNalogaId
WHERE a.RobaSkart = #bool AND
UslugeNaloga.RadniNalogID = #radniNalogID;
Note: If you want to ensure that the rows are returned in the order specified by num_row, you should add ORDER BY num_row to the query.

SQL WHERE statement returning both or conditions

I'm trying to return a single row based on this where statement
WHERE
(C.id = G.community_id
AND P.service_type_id = G.service_type_id
AND I.unit_class_id = G.unit_class_id)
OR
(C.id = G.community_id
AND P.service_type_id = G.service_type_id)
The issue is I have to get a row based on multiple criteria and the more that match determines the final match. The statement above returns a row just fine if it matches the bottom or statement, but if it matches the first OR it returns results for both statements.
LIMIT 1 doesn't work either as sometimes it gives preference to the wrong result.
EDIT:
community_id
service_type_id
unit_class_id
1
1
1
1
1
null
Because of the way the table is both rows are true, my understanding was SQL took the first one that was true and returned it.
I apologize for not a lot of info I was hoping maybe there was just a bit of info I was missing. Here is my query.
CREATE VIEW view_invoice_line_item_gl_code
AS
SELECT
DISTINCT(ILI.invoice_line_item_id) AS invoice_line_item_id,
C.community_id AS community_id,
S.service_type_id AS service_type_id,
U.unit_class_id AS unit_class_id,
LIP.line_item_provider_id AS line_item_provider_id,
(SELECT gl_code_id
FROM gl_code G
WHERE (C.community_id = G.community_id
AND P.service_type_id = G.service_type_id)
AND ((G.unit_class_id IS NULL
AND G.line_item_provider_id IS NULL)
OR
(I.unit_class_id = G.unit_class_id
AND G.line_item_provider_id IS NULL)
OR
(I.unit_class_id = G.unit_class_id
AND ILI.line_item_provider_id = G.line_item_provider_id)
)) AS gl_code_id
FROM
invoice I
JOIN
invoice_line_item ILI ON (ILI.invoice_id = I.invoice_id)
JOIN
invoice_header IH ON (I.invoice_header_id = IH.invoice_header_id)
JOIN
provider_community_account PC ON (I.provider_community_account_id = PC.provider_community_account_id)
JOIN
line_item_provider LIP ON (ILI.line_item_provider_id = LIP.line_item_provider_id)
JOIN
unit_class U ON (I.unit_class_id = U.unit_class_id)
JOIN
community C ON (PC.community_id = C.community_id)
JOIN
provider P ON (PC.provider_id = P.provider_id)
JOIN
service_type S ON (P.service_type_id = S.service_type_id)
I'm assuming that you want to get the record that matches the most conditions first. One way to do that is to order by the number of matching conditions (in this case only one condition is different):
SELECT TOP 1 ...
FROM ...
WHERE
C.id = G.community_id
AND P.service_type_id = G.service_type_id
ORDER BY CASE WHEN I.unit_class_id = G.unit_class_id THEN 1 ELSE 0 END DESC
The first condition implies the second, so you can simplify it like this:
WHERE
C.id = G.community_id
AND P.service_type_id = G.service_type_id
You say where (A AND B) OR A so where A is sufficient.
You'll need to compute a "score" somehow. If you consider each predicate awards 1 point, then you could do something like:
select *
from (
select *,
case when <predicate1> then 1 else 0 end +
case when <predicate2> then 1 else 0 end as score
from t
WHERE
(C.id = G.community_id
AND P.service_type_id = G.service_type_id
AND I.unit_class_id = G.unit_class_id
)
OR
(
C.id = G.community_id
AND P.service_type_id = G.service_type_id
)
)
ORDER BY score DESC
LIMIT 1

How to get fields from multiple tables

I want to get fields from 2 different tables . The last field candidate_score_id has a many to one relationship. So how should I join the below 2 queries
1) To get candidate_score_id from the candidate_score table.
select candidate_score_id from candidate_score a where
a.assessment_id = NEW.assessment_id and
a.candidate_id = NEW.candidate_id and
a.attempt_Count = NEW.attempt_count;
2) To insert different fields in to the candidate_score_details table. The field in this table should be obtained by query above.
insert into candidate_score_details(candidate_score_details_id, candidate_id, assessment_id, attempt_count, score_type, score_tag,correct, candidate_score_id)
select uuid();
select a.candidate_id, a.assessment_id,a.attempt_count,"BY-COMPLEXITY",
case c.complexity
when 1 then "HIGH"
when 2 then "MEDIUM"
when 3 then "LOW"
end, count(*) from candidate_answer a, answer_key b, question_meta_data c where a.candidate_id = NEW.candidate_id and
a.assessment_id = NEW.assessment_id and
a.attempt_count = NEW.attempt_count and
a.assessment_id = b.assessment_id and
a.question_id = b.question_number and
a.response = b.answer and
a.question_id = c.question_number
group by a.candidate_id, a.assessment_id, a.attempt_count, c.complexity;
Just looking at the SQL joining aspect of your question, you'll need to specify the table I THINK you're aliasing a 2nd table with the "NEW" reference. If that's the case, then the query would be (replacing "OTHER_TABLE_NAME" with the name of the 2nd table:
select a.candidate_score_id
from candidate_score a
left join OTHER_TABLE_NAME new on
and a.assessment_id = NEW.assessment_id
and a.candidate_id = NEW.candidate_id
and a.attempt_Count = NEW.attempt_count
Seems that Query 1 has the same 3 criteria on the "candidate_score" table as for the "candidate_answer" table in Query 2.
So how about adding a LEFT JOIN of "candidate_score" to "candidate_answer" on those 3 fields?
For example:
INSERT INTO candidate_score_details
(
candidate_score_details_id,
candidate_id,
assessment_id,
attempt_count,
score_type,
score_tag,
correct,
candidate_score_id
)
SELECT
uuid(),
answer.candidate_id,
answer.assessment_id,
answer.attempt_count,
'BY-COMPLEXITY' AS score_type,
(CASE meta.complexity
WHEN 1 THEN 'HIGH'
WHEN 2 THEN 'MEDIUM'
WHEN 3 THEN 'LOW'
END) AS score_tag,
COUNT(*) AS correct,
MAX(score.candidate_score_id) AS max_candidate_score_id
FROM candidate_answer AS answer
JOIN answer_key AS akey
ON (akey.assessment_id = answer.assessment_id AND akey.question_number = answer.question_id AND akey.answer = answer.response)
LEFT JOIN candidate_score AS score
ON (score.candidate_id = answer.candidate_id AND score.assessment_id = answer.assessment_id AND score.attempt_count = answer.attempt_count)
LEFT JOIN question_meta_data AS meta
ON meta.question_number = answer.question_id
WHERE answer.candidate_id = NEW.candidate_id
AND answer.assessment_id = NEW.assessment_id
AND answer.attempt_count = NEW.attempt_count
GROUP BY answer.candidate_id, answer.assessment_id, answer.attempt_count, meta.complexity;

Why different results to two different ways of writing query

I am trying to understand why the following two SQL statements give different results. The first works as expected, the second produces no records.
Select * from Jet.LayoutListItemEntity_Default itemDefault
Join Jet.LayoutListEntity b
on itemDefault.UiKey = b.UiKey
Left join (Select * from Jet.LayoutListItemEntity where DomainId =2) item
on itemDefault.BindingPath = item.BindingPath
where item.DomainId is null
and b.DomainId = 2
Select * from Jet.LayoutListItemEntity_Default itemDefault
Join Jet.LayoutListEntity b
on itemDefault.UiKey = b.UiKey
Left join Jet.LayoutListItemEntity item
on itemDefault.BindingPath = item.BindingPath
where item.DomainId is null
and item.DomainId = 2
and b.DomainId = 2
The primary difference is that one puts the item.DomainId = 2 at the end, instead of in it's own select. It seems to me they would produce the same results.
Greg
These conditions are mutually exclusive:
where item.DomainId is null
and item.DomainId = 2
item.DomainID can't simultaneously be NULL and 2
You can move the errant where criteria to the JOIN criteria:
Select * from Jet.LayoutListItemEntity_Default itemDefault
Join Jet.LayoutListEntity b
on itemDefault.UiKey = b.UiKey
Left join Jet.LayoutListItemEntity item
on itemDefault.BindingPath = item.BindingPath
and item.DomainId = 2
where item.DomainId is null
and b.DomainId = 2
Your WHERE criteria is messed up in the 2nd query -- to make those statements the same, move the and item_DomainId = 2 to the JOIN.
Select * from Jet.LayoutListItemEntity_Default itemDefault
Join Jet.LayoutListEntity b
on itemDefault.UiKey = b.UiKey
Left join Jet.LayoutListItemEntity item
on itemDefault.BindingPath = item.BindingPath and item.DomainId = 2
where item.DomainId is null
and b.DomainId = 2

how to write this query using joins?

i have a table campaign which has details of campaign mails sent.
campaign_table: campaign_id campaign_name flag
1 test1 1
2 test2 1
3 test3 0
another table campaign activity which has details of campaign activities.
campaign_activity: campaign_id is_clicked is_opened
1 0 1
1 1 0
2 0 1
2 1 0
I want to get all campaigns with flag value 3 and the number of is_clicked columns with value 1 and number of columns with is_opened value 1 in a single query.
ie. campaign_id campaign_name numberofclicks numberofopens
1 test1 1 1
2 test2 1 1
I did this using sub-query with the query:
select c.campaign_id,c.campaign_name,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofclicks,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofopens
FROM
campaign c
WHERE c.flag=1
But people say that using sub-queries are not a good coding convention and you have to use join instead of sub-queries. But i don't know how to get the same result using join. I consulted with some of my colleagues and they are saying that its not possible to use join in this situation. Is it possible to get the same result using joins? if yes, please tell me how.
This should do the trick. Substitute INNER JOIN for LEFT OUTER JOIN if you want to include campaigns which have no activity.
SELECT
c.Campaign_ID
, c.Campaign_Name
, SUM(CASE WHEN a.Is_Clicked = 1 THEN 1 ELSE 0 END) AS NumberOfClicks
, SUM(CASE WHEN a.Is_Opened = 1 THEN 1 ELSE 0 END) AS NumberOfOpens
FROM
dbo.Campaign c
INNER JOIN
dbo.Campaign_Activity a
ON a.Campaign_ID = c.Campaign_ID
GROUP BY
c.Campaign_ID
, c.Campaign_Name
Assuming is_clicked and is_opened are only ever 1 or 0, this should work:
select c.campaign_id, c.campaign_name, sum(d.is_clicked), sum(d.is_opened)
from campaign c inner join campaign_activity d
on c.campaign_id = d.campaign_id
where c.flag = 1
group by c.campaign_id, c.campaign_name
No sub-queries.
Hmm. Is what you want as simple as this? I'm not sure I'm reading the question right...
SELECT
campaign_table.campaign_id, SUM(is_clicked), SUM(is_opened)
FROM
campaign_table
INNER JOIN campaign_activity ON campaign_table.campaign_id = campaign_activity.campaign_id
WHERE
campaign_table.flag = 1
GROUP BY
campaign_table.campaign_id
Note that with an INNER JOIN here, you won't see campaigns where there's nothing corresponding in the campaign_activity table. In that circumstance, you should use a LEFT JOIN, and convert NULL to 0 in the SUM, e.g. SUM(IFNULL(is_clicked, 0)).
I suppose this should do it :
select * from campaign_table inner join campaign_activity on campaign_table.id = campaign_activity.id where campaign_table.flag = 3 and campaign_activity.is_clicked = 1 and campaign_activity.is_opened = 1
Attn : this is not tested in a live situation
The SQL in it's simplest form and most robust form is this: (formatted for readability)
SELECT
campaign_table.campaign_ID, campaign_table.campaign_name, Sum(campaign_activity.is_clicked) AS numberofclicks, Sum(campaign_activity.is_open) AS numberofopens
FROM
campaign_table INNER JOIN campaign_activity ON campaign_table.campaign_ID = campaign_activity.campaign_ID
GROUP BY
campaign_table.campaign_ID, campaign_table.campaign_name, campaign_table.flag
HAVING
campaign_table.flag=1;