SQL Server Grouped results containing number and null values - sql

I want to build a query which will return only the phase_ids that contain level_id values of BOTH numeric AND null
In the following example I would expect to return phase_id 1,3
DECLARE #tbl TABLE
(phase_id numeric(10,0) null,
type_id numeric(10,0) null,
level_id numeric(10,0) null)
INSERT #tbl VALUES (1,1,1)
INSERT #tbl VALUES (1,2,1)
INSERT #tbl VALUES (1,5,2)
INSERT #tbl VALUES (1,1,5)
INSERT #tbl VALUES (1,1,NULL)
INSERT #tbl VALUES (2,1,2)
INSERT #tbl VALUES (2,3,6)
INSERT #tbl VALUES (2,1,1)
INSERT #tbl VALUES (3,1,6)
INSERT #tbl VALUES (3,1,NULL)
SELECT * FROM #tbl
Thank you

count(*) counts all rows, count(level_id) counts non-null rows:
select phase_id
from tbl
group by phase_id
having count(*) <> count(level_id)
and count(level_id) > 0

Related

How do you count the number of rows in a table that have the same value in value in a column?

Suppose I have the following simple table:
create table mytable (
desid bigint not null,
ancid bigint not null
);
insert into mytable (ancid,desid) values (1,10);
insert into mytable (ancid,desid) values (1,20);
insert into mytable (ancid,desid) values (1,21);
insert into mytable (ancid,desid) values (1,22);
insert into mytable (ancid,desid) values (2,30);
insert into mytable (ancid,desid) values (3,40);
insert into mytable (ancid,desid) values (3,41);
insert into mytable (ancid,desid) values (3,42);
insert into mytable (ancid,desid) values (3,43);
What is the SQL command that will print out the following information:
4 rows with ancid=1
1 rows with ancid=2
4 rows with ancid=3
You can get the information by grouping by the ancid:
SELECT ancid, COUNT(*)
FROM mytable
GROUP BY ancid

SQL Filter rows based on multiple distinct values of a column

Given the following table
DECLARE #YourTable TABLE (id int, PLU int, Siteid int, description varchar(50))
INSERT #YourTable VALUES (1, 8972, 2, 'Beer')
INSERT #YourTable VALUES (2, 8972, 3, 'cider')
INSERT #YourTable VALUES (3, 8972, 4, 'Beer')
INSERT #YourTable VALUES (4, 8973, 2, 'Vodka')
INSERT #YourTable VALUES (5, 8973, 3, 'Vodka')
INSERT #YourTable VALUES (6, 8973, 4, 'Vodka')
I trying to write a query that would give me all rows that have multiple distinct values for a given description value against a plu.
So in the example above I would want to return rows 1,2,3 as they have both a 'cider' value and a 'beer' value for a plu of '8972'.
I thought 'GROUP BY' and 'HAVING' was the way to go but I can't seem to get it to work correctly.
SELECT P.PLU, P.Description
FROM #YourTable P
GROUP BY P.PLU, P.Description
HAVING COUNT(DISTINCT(P.DESCRIPTION)) > 1
Any help appreciated.
You shouldn't GROUP BY the description if you are doing a DISTINCT COUNT on it (then it will always be just 1). Try something like this:
SELECT P2.PLU, P2.Description
FROM #YourTable P2
WHERE P2.PLU in (
SELECT P.PLU
FROM #YourTable P
GROUP BY P.PLU
HAVING COUNT(DISTINCT(P.DESCRIPTION)) > 1
)

SQL Finding multiple combinations in 2 tables (with all records)

I have two tables, one with some user configurations (#USERCONFIG) and the other (#COMBINATIONS), multiples combinations of configurations I need to find in the first table.
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU CHAR(10))
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10))
INSERT INTO #COMBINATIONS VALUES (1, 'ABC300')
INSERT INTO #COMBINATIONS VALUES (1, 'ABC400')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC100')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC500')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC200')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC300')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC400')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC600')
With this example data, I want the resultset to look like this:
'SMITHJ', '2'
'SMITHA', '1'
'SMITHC', '2'
Where it will return all users that have a match of configurations from the combinations table.
Any help would be appreciated.
The following will list users and the complete combinations they have. If it helps, you can think of it as the recipe-ingredient and user-ingredient textbook problem:
SELECT alluser.USERID, index_menu.INDEX1
FROM (SELECT DISTINCT USERID FROM #USERCONFIG) AS alluser
CROSS JOIN #COMBINATIONS AS index_menu
LEFT JOIN #USERCONFIG AS user_menu ON alluser.USERID = user_menu.USERID AND index_menu.MENU = user_menu.MENU
GROUP BY alluser.USERID, index_menu.INDEX1
HAVING COUNT(index_menu.MENU) = COUNT(user_menu.MENU)
This snippet will get that result:
IF OBJECT_ID('tempdb..#COMBINATIONS') IS NOT NULL DROP TABLE #COMBINATIONS;
IF OBJECT_ID('tempdb..#USERCONFIG') IS NOT NULL DROP TABLE #USERCONFIG;
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU VARCHAR(10));
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10));
INSERT INTO #COMBINATIONS (INDEX1, MENU) VALUES
(1, 'ABC301'),
(1, 'ABC401'),
(2, 'ABC102'),
(2, 'ABC502'),
(2, 'ABC602');
INSERT INTO #USERCONFIG (USERID, MENU) VALUES
('SMITHJ', 'ABC102'),
('SMITHJ', 'ABC502'),
('SMITHJ', 'ABC602'),
('SMITHC', 'ABC102'),
('SMITHC', 'ABC502'),
('SMITHA', 'ABC102'),
('SMITHA', 'ABC200'),
('SMITHA', 'ABC301'),
('SMITHA', 'ABC401'),
('SMITHA', 'ABC602');
SELECT USERID, INDEX1
FROM
(
SELECT uconf.USERID, comb.INDEX1,
COUNT(*) AS Total,
DENSE_RANK() OVER (PARTITION BY uconf.USERID ORDER BY COUNT(*) DESC, comb.INDEX1 ASC) AS Rnk
FROM #USERCONFIG uconf
INNER JOIN #COMBINATIONS comb
ON comb.MENU = uconf.MENU
GROUP BY uconf.USERID, INDEX1
) q
WHERE Rnk = 1
ORDER BY Total DESC, USERID;
Returns:
USERID INDEX1
SMITHJ 2
SMITHA 1
SMITHC 2

Output elements between specific element

Suppose I have a table with a column which looks like:
SELECT Col1
FROM table;
Col1
A
A
B
B
C
C
D
B
E
B
F
I would like to output elements that are between "B"s, which are C, D, E
How can I do that with a query?
declare #t table (ID INT IDENTITY(1,1),col1 VARCHAR(10))
insert into #t (col1) values ('A')
insert into #t (col1) values ('A')
insert into #t (col1) values ('B')
insert into #t (col1) values ('B')
insert into #t (col1) values ('C')
insert into #t (col1) values ('C')
insert into #t (col1) values ('B')
insert into #t (col1) values ('E')
insert into #t (col1) values ('B')
insert into #t (col1) values ('F')
select ID,col1 from #t
where ID between (select MIN(id) from #t WHERE col1 = 'B') and
(select MAX(id) from #t WHERE col1 = 'B')
and col1<>'B'

A simple but challenging SQL Question, at least I couldn't find a way out except doing it externally (c#)

I have an SQL Table which consists of 1 column only
Column Name
A
A
A
B
B
B
B
C
D
D
E
I need an SQL Code that returns the cut points. For the table above, it will return this:
Column Name
3
7
8
10
11
3 is the end of A's and 7 is the end of B's and 8 is the end of C's and so on...
Let's see what can you come up with :=)
Assuming the data can be sorted on your Column, the plan is to generate a row number for each row and do a group by to retrieve your data points.
SQL Server 2000
DECLARE #YourTable TABLE (Col VARCHAR(1))
CREATE TABLE #TempTable (ID INTEGER IDENTITY(1, 1), Col VARCHAR(1))
SET IDENTITY_INSERT #TempTable OFF
INSERT INTO #YourTable (Col) VALUES ('A')
INSERT INTO #YourTable (Col) VALUES ('A')
INSERT INTO #YourTable (Col) VALUES ('A')
INSERT INTO #YourTable (Col) VALUES ('B')
INSERT INTO #YourTable (Col) VALUES ('B')
INSERT INTO #YourTable (Col) VALUES ('B')
INSERT INTO #YourTable (Col) VALUES ('B')
INSERT INTO #YourTable (Col) VALUES ('C')
INSERT INTO #YourTable (Col) VALUES ('D')
INSERT INTO #YourTable (Col) VALUES ('D')
INSERT INTO #YourTable (Col) VALUES ('E')
INSERT INTO #TempTable
SELECT *
FROM #YourTable
ORDER BY Col
SELECT MAX(ID)
FROM #TempTable
GROUP BY Col
DROP TABLE #TempTable
SQL Server 2005
DECLARE #Table TABLE (Col VARCHAR(1))
INSERT INTO #Table VALUES ('A')
INSERT INTO #Table VALUES ('A')
INSERT INTO #Table VALUES ('A')
INSERT INTO #Table VALUES ('B')
INSERT INTO #Table VALUES ('B')
INSERT INTO #Table VALUES ('B')
INSERT INTO #Table VALUES ('B')
INSERT INTO #Table VALUES ('C')
INSERT INTO #Table VALUES ('D')
INSERT INTO #Table VALUES ('D')
INSERT INTO #Table VALUES ('E')
SELECT MAX(RowNumber)
FROM (SELECT RowNumber = ROW_NUMBER() OVER (ORDER BY Col), Col
FROM #Table) t
GROUP BY Col
with endings(columnname, ending) as
(
select columnname, row_number() over (order by columnname) as 'ending'
from theTable
)
select max(ending)
from endings
group by columnname
Solution for Oracle:
Assuming the name of the column is COL1,
SELECT COL1,MAX(ROWNUM)
FROM TEST_CHARS
GROUP BY COL1
ORDER BY COL1;