SQL WHERE IN two column with specific combinations - sql

I am using Oracle 10g database. I have a data table with the following data :
name groupid subgroupid
checklist1 1 12
checklist2 1 4
checklist3 2 4
My query :
select * from checklist
where groupid IN (1, 2) AND subgroupid IN (12, 4);
The result that I am getting :
name groupid subgroupid
checklist1 1 12
checklist2 1 4
checklist3 2 4
The result that I want :
name groupid subgroupid
checklist1 1 12
checklist3 2 4
I could do :
select * from checklist
where (groupid = 1 AND subgroupid = 12)
OR (groupid = 2 AND subgroupid = 4)
I could do the above but bare in my that I would have to create a long and unclean code for the query string to be executed. Is there some clean and shortcut way to get more specific data I am looking for using the combination of groupid and subgroupid

Some databases support tuple operations for in, so you could do:
where (groupid, subgroupid) IN ((1, 12), (2, 4))
You don't mention what database you are using, so this is a possibility.
Otherwise, the explicit comparisons are a reasonable option.
Or, alternatively, a join to a derived table, which might look like this:
select cl
from checklist cl join
(select 1 as groupid, 12 as subgroupid union all
select 2, 4
) x
on cl.groupid = x.groupid and cl.subgroupid = x.subgroupid;

Your can use the help of cte also.
With cte_grp
AS
(select 1 as GroupId, 12 as SubGroupId
UNION
select 2, 4
)
SELECT c.*
FROM checklist c
JOIN cte_grp cg on c.GroupId=cg.GroupId
AND c.SubGroupId=cg.SubGroupId

Related

SQL, order by data entered

I wasn't quite sure how to word this question. But if you imagine I have:
var contents = "5, 7, 1, 3, 4";
And I want to do a query:
SELECT id,name FROM db WHERE id in (contents);
I would get the following response (a):
ID NAME
1 ONE
3 THREE
4 FOUR
5 FIVE
7 SEVEN
But in reality, I want it to be ordered by the order of contents, i.e (b):
ID NAME
5 FIVE
7 SEVEN
1 ONE
3 THREE
4 FOUR
Is there anyway to have the resposne ordered as b and not a
An ANSI SQL method uses a giant case expression:
SELECT id,name
FROM db
WHERE id in (contents)
ORDER BY (CASE id WHEN 5 THEN 1 WHEN 7 THEN 2 WHEN 1 THEN 3 WHEN 3 THEN 4 WHEN 4 THEN 5 END);
With standard ANSI SQL you could join to a list of values that specify the sort order:
select t.*
from the_table t
join (
values
(5, 1),
(7, 2),
(1, 3),
(3, 4),
(4, 5)
) as s (id, sort_order) on t.id = s.id
order by s.sort_order ;
Online example: http://rextester.com/UDW37167

MSSQL ORDER BY Passed List

I am using Lucene to perform queries on a subset of SQL data which returns me a scored list of RecordIDs, e.g. 11,4,5,25,30 .
I want to use this list to retrieve a set of results from the full SQL Table by RecordIDs.
So SELECT * FROM MyFullRecord
where RecordID in (11,5,3,25,30)
I would like the retrieved list to maintain the scored order.
I can do it by using an Order by like so;
ORDER BY (CASE WHEN RecordID = 11 THEN 0
WHEN RecordID = 5 THEN 1
WHEN RecordID = 3 THEN 2
WHEN RecordID = 25 THEN 3
WHEN RecordID = 30 THEN 4
END)
I am concerned with the loading of the server loading especially if I am passing long lists of RecordIDs. Does anyone have experience of this or how can I determine an optimum list length.
Are there any other ways to achieve this functionality in MSSQL?
Roger
You can record your list into a table or table variable with sorting priorities.
And then join your table with this sorting one.
DECLARE TABLE #tSortOrder (RecordID INT, SortOrder INT)
INSERT INTO #tSortOrder (RecordID, SortOrder)
SELECT 11, 1 UNION ALL
SELECT 5, 2 UNION ALL
SELECT 3, 3 UNION ALL
SELECT 25, 4 UNION ALL
SELECT 30, 5
SELECT *
FROM yourTable T
LEFT JOIN #tSortOrder S ON T.RecordID = S.RecordID
ORDER BY S.SortOrder
Instead of creating a searched order by statement, you could create an in memory table to join. It's easier on the eyes and definitely scales better.
SQL Statement
SELECT mfr.*
FROM MyFullRecord mfr
INNER JOIN (
SELECT *
FROM (VALUES (1, 11),
(2, 5),
(3, 3),
(4, 25),
(5, 30)
) q(ID, RecordID)
) q ON q.RecordID = mfr.RecordID
ORDER BY
q.ID
Look here for a fiddle
Something like:
SELECT * FROM MyFullRecord where RecordID in (11,5,3,25,30)
ORDER BY
CHARINDEX(','+CAST(RecordID AS varchar)+',',
','+'11,5,3,25,30'+',')
SQLFiddle demo

Find duplicate groups of rows in SQL Server

I have a table with materials information where one material has from one to many constituents.
The table looks like this:
material_id contstiuent_id constituent_wt_pct
1 1 10.5
1 2 89.5
2 1 10.5
2 5 15.5
2 7 74
3 1 10.5
3 2 89.5
Generally, I can have different material ID's with the same constituents (both ID's and weight percent), but also the same constituent id with the same weight percent can be in multiple materials.
I need to find the material ID's that have exactly the same amount of constituents, same constituents id's and same weight percent (in the example of data that will be material ID 1 and 3)
What would be great is to have the output like:
ID Duplicate ID's
1 1,3
2 15,25
....
Just to clarify the question: I have several thousands of materials and it won't help me if I get just the id's of duplicate rows - I would like to see if it is possible to get the groups of duplicate material id's in the same row or field.
Build a XML string in a CTE that contains all constituents and use that string to figure out what materials is duplicate.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table Materials
(
material_id int,
constituent_id int,
constituent_wt_pct decimal(10, 2)
);
insert into Materials values
(1, 1, 10.5),
(1, 2, 89.5),
(2, 1, 10.5),
(2, 5, 15.5),
(2, 7, 74),
(3, 1, 10.5),
(3, 2, 89.5);
Query 1:
with C as
(
select M1.material_id,
(
select M2.constituent_id as I,
M2.constituent_wt_pct as P
from Materials as M2
where M1.material_id = M2.material_id
order by M2.constituent_id,
M2.material_id
for xml path('')
) as constituents
from Materials as M1
group by M1.material_id
)
select row_number() over(order by 1/0) as ID,
stuff((
select ','+cast(C2.material_id as varchar(10))
from C as C2
where C1.constituents = C2.constituents
for xml path('')
), 1, 1, '') as MaterialIDs
from C as C1
group by C1.constituents
having count(*) > 1
Results:
| ID | MATERIALIDS |
--------------------
| 1 | 1,3 |
Well you can use the following code to get the duplicate value,
Select EMP_NAME as NameT,count(EMP_NAME) as DuplicateValCount From dbo.Emp_test
group by Emp_name having count(EMP_NAME) > 1

How do I SELECT such that a group by column has every value from supplied list in another coumn

In MS SQL Server 2008, have a table like the following:
CREATE TABLE SomeTable
(
MajorID int NOT NULL REFERENCES ...,
MinorID int NOT NULL,
Value int NOT NULL REFERENCES ...,
PRIMARY KEY(MajorID, MinorID)
)
I also have a set of (Value0, Value1, ...). The goal is to find all such MajorID that have every Value from the set listed at least once. MinorID is not important in this task. The size of set is not predefined, and the set is generated in client application. There's a reasonable limit on its maximum size, say, 64.
What SQL should I use?
Example:
MajorID MinorID Value
1 0 4
1 1 1
1 2 3
1 3 4
1 4 4
1 5 5
1 6 5
2 0 1
3 0 1
3 1 4
For value list (1, 4) the answer is (1, 3), because MajorID 1 and 3 have each value listed at least once.
You can do this with aggregation, as in this query:
select majorid
from t
group by majorid
having COUNT(distinct value) = (select COUNT(distinct value) from t)
The having clause checks that all values are there for a majorid.
This is for all values. If you have a value list, then try this:
with valuelist as (
select 1 as vslue union all
select 4
)
select majorid
from t join
valuelist vl
on t.value = vl.value
group by majorid
having count(distinct value) = (select count(*) from valuelist)
This is the simple way:
select majorid
from ReportStack
where value in (1, 3)
group by majorid
having count (distinct value) = 2
The only maintenance issue with this query is making sure the having clause value (2 in this query) is the same as size of the target value list.

Custom order in SQL

We are querying database to retrieve data in following fashion
select a,b,...f from table1 where id in (6,33,1,78,2)
The result I got from query is in following order 1,2,6,33,78.
I want the result in same order (6,33,1,78,2). Is there any way to retrieve the data in same order.
EDIT
*I am using SQL 2008*
add this order by clause
order by case
when id = 6 then 1
when id = 33 then 2
when id = 1 then 3
when id = 78 then 4
when id = 2 then 5
end
If using MySQL you can do this
ORDER BY FIND_IN_SET(id, '6,33,1,78,2')
Using a Table Value Constructor:
SELECT a, b, ... f
FROM
table1
JOIN
( VALUES
(1, 6),
(2, 33),
(3, 1),
(4, 78),
(5, 2)
) AS ordering (position, id)
ON ordering.id = table1.id
ORDER BY position
I don't know the background, but usually I achieve this custom order in an additional orderIndex column. This way I can manually manage the order when inserting to the table and add this column to the ORDER BY clause of the default queries
If you use SQL Server you could use charindex.
select A, B
from Table1
where ID in (6,33,1,78,2)
order by charindex(','+cast(ID as varchar(10))+',', ',6,33,1,78,2,')
ugly solution:
select a,b,...f from table1 where id in 6
UNION
select a,b,...f from table1 where id in 33
and so on..
"better" solution:
add another column on your query and do case 6 then 0, case 33 then 1 and so on
select a,b,...f , case id when 6 then 0 when 33 then 1 <and so on> end
from table1 where ...
and then order by this new column