What sql statement will give me this result? - sql-server

I do not know how to word my question properly. My apologies for that. I have a table like this:
EventId | Item | Type
--------+------+------
1 | 123 | A
2 | 123 | B
3 | 123 | C
4 | 456 | A
5 | 456 | B
I want to select only those items that do not have event of type C. Then only show event of type B of those items. So, the result should look like this:
EventId | Item | Type
--------+------+-------
5 | 456 | B

This should do the trick...
IF OBJECT_ID('tempdb..#Event', 'U') IS NOT NULL
DROP TABLE #Event;
CREATE TABLE #Event (
EventId INT NOT NULL PRIMARY KEY,
Item INT NOT NULL,
ItemType CHAR(1) NOT NULL
);
INSERT #Event (EventId, Item, ItemType) VALUES
(1, 123, 'A'),
(2, 123, 'B'),
(3, 123, 'C'),
(4, 456, 'A'),
(5, 456, 'B');
--=======================================
SELECT
e1.EventId, e1.Item, e1.ItemType
FROM
#Event e1
WHERE
e1.ItemType = 'B'
AND NOT EXISTS (
SELECT 1
FROM #Event e2
WHERE
e1.Item = e2.Item
AND e2.ItemType = 'C'
);
Results...
EventId Item ItemType
----------- ----------- --------
5 456 B

You answer based on said constrain
SELECT
e1.EventId, e1.Item, e1.ItemType
FROM
Event e1
INNER JOIN Event e2 ON e1.Item != e2.Item
WHERE e1.ItemType = 'B'
AND e2.ItemType = 'C'
Output:
Note: Inner SELECT query may cause the performance issue while processing large number of records comparing to INNER JOIN

Related

How to efficiently find minimum associated ID after applying transitivity

I've a very large table with ID variables in two columns. I'd like to find the minimum associated ID after applying transitivity. For example, if ID1 = 1 and ID2 = 2 for one record and ID1 = 2 and ID2 = 3 for another record, I'd like the results to ultimately yield three records where the first column has an ID (1, 2, and 3) and the second column has a Min_ID (all equal to 1, in the above example).
I've determined that at most there are 6 ways IDs can be related, and I believe the below is a minimum functioning example.
Is there a more efficient way to do this?
Source
| ID1 | ID2 |
|------|-------|
| 1 | 1 |
| 2 | 2 |
| 1 | 1 |
| 1 | 2 |
| 2 | 11 |
| 11 | 13 |
| 13 | 99 |
| 99 | 1000 |
| 1000 | 97887 |
| 3 | 5 |
| 5 | 17 |
| 17 | 19 |
| 23 | 34 |
Results
| ID | Min_ID |
|-------|--------|
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 5 | 3 |
| 11 | 1 |
| 13 | 1 |
| 17 | 3 |
| 19 | 3 |
| 23 | 23 |
| 34 | 23 |
| 99 | 1 |
| 1000 | 1 |
| 97887 | 1 |
Functioning albeit potentially-inefficient working example:
IF OBJECT_ID('tempdb..##IDs') IS NOT NULL DROP TABLE ##IDs
GO
CREATE TABLE ##IDs
(
ID1 int
,ID2 int
);
INSERT INTO ##IDs (ID1, ID2)
VALUES
(1, 1),
(2, 2),
(1, 1),
(1, 2),
(2, 11),
(11, 13),
(13, 99),
(99, 1000),
(1000, 97887),
(3, 5),
(5, 17),
(17, 19),
(23, 34)
;
WITH t1 AS
(
SELECT
ID1
,ID2
FROM ##IDs
UNION
SELECT
ID2
,ID1
FROM ##IDs
),
t2 AS
(
SELECT
*
FROM t1
UNION
SELECT
a.ID1
,b.ID2
FROM t1 a
LEFT JOIN t1 b ON
a.ID2 = b.ID1
UNION
SELECT
b.ID2
,a.ID1
FROM t1 a
LEFT JOIN t1 b ON
a.ID2 = b.ID1
),
t3 AS
(
SELECT
*
FROM t2
UNION
SELECT
a.ID1
,b.ID2
FROM t2 a
LEFT JOIN t2 b ON
a.ID2 = b.ID1
UNION
SELECT
b.ID2
,a.ID1
FROM t2 a
LEFT JOIN t2 b ON
a.ID2 = b.ID1
),
t4 AS
(
SELECT
*
FROM t3
UNION
SELECT
a.ID1
,b.ID2
FROM t3 a
LEFT JOIN t3 b ON
a.ID2 = b.ID1
UNION
SELECT
b.ID2
,a.ID1
FROM t3 a
LEFT JOIN t3 b ON
a.ID2 = b.ID1
)
SELECT
ID1 AS [ID]
,MIN(ID2) Min_ID
FROM t4
GROUP BY
ID1
The complexity here for me was finding an appropriate stopping condition for the linking recursion. That said, it's really quite simple: stop linking when the ID links to itself.
IF OBJECT_ID('tempdb..##IDs') IS NOT NULL DROP TABLE ##IDs
GO
CREATE TABLE ##IDs
(
ID1 int
,ID2 int
);
INSERT INTO ##IDs (ID1, ID2)
VALUES
(1, 1),
(2, 2),
(1, 1),
(1, 2),
(2, 11),
(11, 13),
(13, 99),
(99, 1000),
(1000, 97887),
(3, 5),
(5, 17),
(17, 19),
(23, 34)
;
WITH t1 AS
(
SELECT
ID1
,ID2
FROM ##IDs
UNION
SELECT
ID2
,ID1
FROM ##IDs
UNION ALL
SELECT
c.ID1
,t1.ID2
FROM ##IDs c
INNER JOIN t1 ON
c.ID2 = t1.ID1
WHERE
c.ID1 <> c.ID2
UNION ALL
SELECT
t1.ID2
,c.ID1
FROM ##IDs c
INNER JOIN t1 ON
c.ID2 = t1.ID1
WHERE
c.ID1 <> c.ID2
)
SELECT
ID1 AS [ID]
,MIN(ID2) Min_ID
FROM t1
GROUP BY
ID1
;

Generate report from a table

I have a table like:
+====+========+========+
| Id | name | value |
+====+========+========+
| 1 | a | 7 |
+----+--------+--------+
| 2 | c | 7 |
+----+--------+--------+
| 1 | g | 1 |
+----+--------+--------+
| 2 | c | 2 |
+----+--------+--------+
| 4 | g | 5 |
+----+--------+--------+
| 6 | t | 4 |
+----+--------+--------+
I need to write two (2) queries to generate two reports, according to this two conditions:
Report Output1=if id and name same (id,name,val)
Report Output2=if id same but different name(id,name,val)
How to write those two queries?
Your conditions is not clear, but mybe this what you want:
DECLARE #T TABLE (Id INT, Name VARCHAR(25), Value INT);
DECLARE #YourId INT = 1;
DECLARE #YourName VARCHAR(25) ='a';
/**/
INSERT INTO #T VALUES
(1, 'a', 7),
(2, 'c', 7),
(1, 'g', 1),
(2, 'c', 2),
(4, 'g', 5),
(6, 't', 4);
/*First query*/
SELECT *
FROM #T
WHERE ID = #YourID AND Name = #YourName;
/*Second query*/
SELECT *
FROM #T
WHERE ID = #YourID;
If you want the result of both queries in one result, then you can use UNION ALL as:
SELECT *
FROM #T
WHERE ID = #YourID AND Name = #YourName
UNION ALL
SELECT *
FROM #T
WHERE ID = #YourID;
Demo.
Well, I am not sure, what OP wanted, but maybe it was something like this?
// records where id and value are the same
SELECT * FROM #T WHERE ID=Value;
// other records having the same ids as abobe, but DIFFERENT values
SELECT * FROM #T WHERE ID IN
(SELECT ID FROM #T WHERE ID=Value)
AND Id!=Value;
Results:
   Id Name Value
1 g 1
2 c 2
   Id Name Value
1 a 7
2 c 7
Thanks to #Sami for providing the fiddle which I modified into this DEMO.

I want to make query to read subject score of student to mark

I have database in SQL Server 2012 with two tables
The first table columns is :
| Student_ID , Subject_ID , Subject_score , Subject_mark |
|--------------------------------------------------------|
| 1 | 1 | 92 | ? |
| 1 | 2 | 88 | ? |
|____________|____________|_______________|______________|
And the second table columns is :
|Score_ID | Subject_mark |
|________________________|
| 100 | A+ |
| 95 | A |
| 90 | B+ |
| 85 | B |
| 80 | c |
| 75 | E |
|_________|______________|
I want to write a query to get Subject_mark from the second table and put it in Subject_mark in the first table
select from Subject_mark on table_1 ranged from table_2
I'm on my phone, so I'll have to check this later, as something seems a bit wrong about it, but try something like
Update table_1
Set Subject_mark = (select Subject_mark from table_2
where Score_ID <= (select Subject_score)
and Score_ID > (select Subject_score - 5))
Sample execution with given sample data:
DECLARE #FirstTable TABLE (Student_ID INT, Subject_ID INT, Subject_score INT, Subject_mark VARCHAR(3))
INSERT INTO #FirstTable (Student_ID, Subject_ID, Subject_score, Subject_mark)
VALUES
(1, 1, 92, NULL),
(1, 2, 88, NULL)
DECLARE #SecondTable TABLE (Score_ID INT, Subject_mark VARCHAR(3))
INSERT INTO #SecondTable (Score_ID, Subject_mark)
VALUES
(100, 'A+'),
(95 , 'A'),
(90 , 'B+'),
(85 , 'B'),
(80 , 'C'),
(75 , 'E')
UPDATE #FirstTable
SET Subject_mark = (SELECT Subject_mark
FROM #SecondTable
WHERE Score_ID <= (SELECT Subject_score) AND
Score_ID > (SELECT Subject_score - 5))
SELECT * FROM #FirstTable
Given that marks are classified at a difference of 5 marks each, this should work.
UPDATE t1
SET t1.Subject_mark = CASE WHEN t1.Subject_score < 75 THEN 'E' ELSE t2.Subject_mark END
FROM FirstTable t1
LEFT OUTER JOIN SecondTable t2 ON t1.Subject_score <= t2.Score_ID AND t1.Subject_score > t2.Score_ID - 5;

SQL JOIN with COALESCE in condition is duplicating rows

I am trying to join two tables together. The first table contains data records that I do not want to duplicate. The second table I am joining to the first table to lookup a [value] by a distinct [profileId] and [role]. The [profileId], [role] column in the second table has a unique constraint on the combination, but [role] can sometimes be NULL, in which case I treat that value as the default for that profile.
How can I join these tables together without duplicating the rows, and without using multiple left joins? My actual query is more complex than the example.
See example below.
DECLARE #temp TABLE ([profileId] int, [role] int)
DECLARE #temp2 TABLE ([profileId] int, [role] int, [value] nvarchar(50))
INSERT INTO #temp ([profileId], [role]) VALUES (1, 1)
INSERT INTO #temp ([profileId], [role]) VALUES (1, 2)
INSERT INTO #temp ([profileId], [role]) VALUES (2, 1)
INSERT INTO #temp ([profileId], [role]) VALUES (2, 2)
INSERT INTO #temp2 ([profileId], [role], [value]) VALUES (1, 1, 'MATCH')
INSERT INTO #temp2 ([profileId], [role], [value]) VALUES (1, NULL, 'DEFAULT1')
INSERT INTO #temp2 ([profileId], [role], [value]) VALUES (2, NULL, 'DEFAULT2')
SELECT
T1.[profileId],
T1.[role],
T2.value
FROM
#temp T1
JOIN #temp2 T2 ON T1.profileId = T2.profileId AND COALESCE(T2.[role], T1.[role]) = T1.[role]
This gives me (and I understand why)
================================
| profileId | role | value |
================================
| 1 | 1 | MATCH |
--------------------------------
| 1 | 1 | DEFAULT1 |
--------------------------------
| 1 | 2 | DEFAULT1 |
--------------------------------
| 2 | 1 | DEFAULT2 |
--------------------------------
| 2 | 2 | DEFAULT2 |
================================
While I want
================================
| profileId | role | value |
================================
| 1 | 1 | MATCH |
--------------------------------
| 1 | 2 | DEFAULT1 |
--------------------------------
| 2 | 1 | DEFAULT2 |
--------------------------------
| 2 | 2 | DEFAULT2 |
================================
This SQL works fine:
SELECT
T1.[role],
Value = coalesce(max(nullif(T2.value,'DEFAULT')),'DEFAULT')
FROM
#temp T1
JOIN #temp2 T2 ON COALESCE(T2.[role], T1.[role]) = T1.[role]
group by
T1.[role]
;
You can use APPLY and TOP:
SELECT
t.profileId,
t.role,
x.value
FROM #temp t
OUTER APPLY(
SELECT TOP 1 value
FROM #temp2
WHERE
profileId = t.profileId
AND (role = t.role OR role IS NULL)
ORDER BY
CASE WHEN role IS NOT NULL THEN 0 ELSE 1 END
)x
if you know the DEFAULT value use left join.
SQL Fiddle Demo
SELECT
T1.[role],
COALESCE(T2.value, 'DEFAULT') as value
FROM
temp T1
LEFT JOIN temp2 T2
ON T1.[role] = T2.[role];
Otherwise
SELECT
T1.[role],
COALESCE(T2.value, (SELECT value
FROM temp2
WHERE role is NULL and temp2.profileID = T1.profileID)) as value
FROM
temp T1
LEFT JOIN temp2 T2
ON T1.[role] = T2.[role]
AND T1.[profileID] = T2.[profileID]
;

Union Two Tables and Overwrite Preexisting Rows

I'm looking to union two tables together, but if there are any duplicate records where "Email" from Table 1 matches "Email" from Table 2, then data from Table 2 will be extracted. Is this function possible?
Table 1
Name | Email | Status
A | a#a.com | 1
B | b#b.com | 2
C | c#c.com | 1
Table 2
Name | Email | Status
C | c#c.com | 2
D | d#d.com | 1
E | e#e.com | 2
Resulting Table
Name | Email | Status
A | a#a.com | 1
B | b#b.com | 2
C | c#c.com | 2
D | d#d.com | 1
E | e#e.com | 2
One approach to this problem is to do a SELECT against table1 with a WHERE NOT IN against table2 to filter the rows selected from table1 so that none of the rows that exist in table2 will be part of that result -- then that result can be UNION'd against table2.
Here's an example (TableA and TableB in my code):
declare #TableA as Table ( Name VarChar(20), Email VarChar(20), Status INT );
declare #TableB as Table ( Name VarChar(20), Email VarChar(20), Status INT );
insert into #TableA ( Name, Email, Status ) values
( 'A', 'a#a.com', 1 ),
( 'B', 'b#b.com', 2 ),
( 'C', 'c#c.com', 1 )
insert into #TableB ( Name, Email, Status ) values
( 'C', 'c#c.com', 2 ),
( 'D', 'd#d.com', 1 ),
( 'E', 'e#e.com', 2 )
SELECT * FROM #TableA WHERE Email NOT IN ( SELECT DISTINCT Email FROM #TableB )
UNION
SELECT * FROM #TableB

Resources