I have a table :
create table a (page int, pro int)
go
insert into a select 1, 2
insert into a select 4, 2
insert into a select 5, 2
insert into a select 9, 2
insert into a select 1, 3
insert into a select 2, 3
insert into a select 3, 3
insert into a select 4, 3
insert into a select 9, 3
insert into a select 1, 4
insert into a select 9, 4
insert into a select 12, 4
insert into a select 1, 5
insert into a select 9, 5
insert into a select 12, 5
insert into a select 13, 5
insert into a select 14, 5
insert into a select 15, 5
go
(here is the SQLfiddle of this table and queries I began to write )
Common value of page on ALL lines
I'm looking to extract the common column "page" for each column "pro" from this table.
here is what we expect :
1
9
I tried to use:
SELECT DISTINCT a.page
FROM a
WHERE a.page IN (
SELECT b.page FROM a as b
WHERE b.pro <> a.pro
)
but this query returns every "page" that have at least one common values which is not what we need to have. see below :
1
4
9
12
The opposite query aka different value at least one but not all time
I'm looking to extract the "page" linked to one or more "pro" but without being common to all of them (it's the exact opposite of the previous query)
Here is what we expect :
2
3
4
5
12
13
14
15
I can't manage to find a solution to those 2 queries :'(
Could anyone help me on those ones?
Best regards
edit: the SQLfiddle url
Just a bit of reversed thinking - group by page and count distinct pro values for each. Return rows that matches the total of distinct pro values
SELECT [page]
FROM a
GROUP BY [page]
HAVING COUNT(DISTINCT pro) = (SELECT COUNT(DISTINCT pro) FROM a)
SQLFiddle
EDIT: for the second problem, just replace = with '<' in the final line -> SQLFiddle
Fot the first part of the question, try this query:
SELECT DISTINCT t1.page FROM a t1
WHERE (SELECT COUNT(DISTINCT t2.pro) FROM a t2 WHERE
t2.page = t1.page) =
(SELECT COUNT(DISTINCT t3.pro) FROM a t3)
And the second query is the simple substraction from all page values:
SELECT DISTINCT t4.page FROM a t4
EXCEPT
SELECT DISTINCT t1.page FROM a t1
WHERE (SELECT COUNT(DISTINCT t2.pro) FROM a t2 WHERE
t2.page = t1.page) =
(SELECT COUNT(DISTINCT t3.pro) FROM a t3)
Related
in my database I have 10 users numbers some of them have been deleted, and when I select the column at shows like this:
missing_user_number:
1,
2,
5,
8,
10,
and I need to know if there is a script that can get the missing numbers like this, I don't want the deleted data back, I just want the missing numbers as an integrs data:
missing_user_number:
3,
4,
6,
7,
9,
In most versions of SQL, it is actually easier to get ranges of missing values, rather than each missing value:
select user_number + 1 as missing_range_start, next_user_number - 1 as missing_range_end
from (select t.*,
lead(user_number) over (order by user_number) as next_user_number
from t
) t
where user_number <> user_number + 1;
Note: This only finds internal missing numbers, as in the example in your question.
You can create an in-line numbers table that contains all 10 user numbers. Then LEFT JOIN your table to it in order to get the missing numbers:
SELECT t1.n AS missing_user_number
FROM (
SELECT 1 AS n UNION ALL SELECT 2 ... SELECT 10
) AS t1
LEFT JOIN mytable AS t2 ON t1.n = t2.user_number
WHERE t2.user_number IS NULL
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
I'm using a numbers matching table, from one upwards. However, I realize I need to start at zero instead. Can't figure it out..
CREATE TABLE IF NOT EXISTS util_nums (n integer primary key
autoincrement not null);
insert into util_nums(n) select null from (select 0 as n union select 1
union select 2 union select 3 union select 4 union select 5 union select 6
union select 7 union select 8 union select 9 union select 10) a
cross join
(select 0 as n union select 1 union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8 union select 9
union select 10) b
cross join (select 0 as n union select 1 union select 2
union select 3 union select 4 union select 5 union select 6 union select 7
union select 8 union select 9 union select 10) c;
in sql server it would be easy if you create your table like this
CREATE TABLE util_nums (n as int primary key
identity(0,1) not null,anotherfieldtoholdthenulls integer);
the identity(0,1) means start from zero and increment by 1 ..
update
try using UPDATE SQLITE_SEQUENCE SET seq = -1 WHERE name = 'util_nums' before starting the insert, and see if it is allowed....
You should also be able to do INSERT INTO util_nums VALUES(0)
Sqlite allows you to insert explicit values for the primary key fields:
insert into util_nums(n) values (0);
to Get a lot more rows insert quickly try this after that..
insert into util_nums default values;
insert into util_nums(n) select null from util_nums a, util_nums b, util_nums c, util_nums d;
insert into util_nums(n) select null from util_nums a, util_nums b, util_nums c, util_nums d;
you can temporarly disable auto increment using
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
But I
suggest update value to 0 after insert
If you're useing SQLite you should probably read this http://www.sqlite.org/autoinc.html . This caught my eye:
If the table has never before
contained any data, then a ROWID of 1
is used.
It doesn't seem to be any way to force autoincrement to start from something other than 1. Also note that it may generate gaps by skipping numbers.
This may work but I have no means of testing at the moment:
Add a row with an ID of -1. Then delete it. It isn't clear from the documentation what happens when you have only negative IDs in the table.
"SQLite Autoincrement"
The important part seems to be...
If no negative ROWID values are inserted explicitly, then automatically
generated ROWID values will always be greater than zero.
So? Create the table, insert a dummy record, with a forced id of -1, and then insert your data. Deleting the dummy record afterwards as/if necessary.
(Inserting a value with -1 will force the next inserted rwo to have an id of 0, assuming the table was otherwise empty.)
SQLite allows you to specify a value here.
Just insert c.n - 1, from your cartesian product, instead of null, and call it a day.
I've received data from an external source, which is in a summarised format. I need a way to disaggregate this to fit into a system I am using.
To illustrate, suppose the data I received looks like this:
receivedTable:
Age Gender Count
40 M 3
41 M 2
I want this is a disaggregated format like this:
systemTable:
ID Age Gender
1 40 M
2 40 M
3 40 M
4 41 M
5 41 M
Thanks
Karl
Depending of the range of your count you could use a lookup table that holds exactly x records for each integer x. Like this:
create table counter(num int)
insert into counter select 1
insert into counter select 2
insert into counter select 2
insert into counter select 3
insert into counter select 3
insert into counter select 3
insert into counter select 4
insert into counter select 4
insert into counter select 4
insert into counter select 4
then join with this table:
create table source(age int, gender char(1), num int)
insert into source select 40, 'm', 3
insert into source select 30, 'f', 2
insert into source select 20, 'm', 1
--insert into destination(age, gender)
select age, gender
from source
inner join counter on counter.num = source.num
From the "Works on my machine (TM)" stable a recursive query, with all the usual caveats about maximum recursion depth.
with Expanded(exAge, exGender, exRowIndex) as
(
select
Age as exAge,
Gender as exGender,
1 as exRowIndex
from
tblTest1
union all
select
exAge,
exGender,
exRowIndex+1
from
tblTest1 t1
inner join
Expanded e on (e.exAge = t1.Age and e.exGender = t1.Gender and e.exRowIndex < t1.Count)
)
select
exAge,
exGender,
exRowIndex
from
Expanded
order by
exAge,
exGender,
exRowIndex
option (MAXRECURSION 0) -- BE CAREFUL!!
You don't get the row identifier - but inserting the result of the query into a table with an identity column would deal with that.
I know I can select multiple rows like this:
select * FROM table WHERE id in (1, 2, 3, 10, 100);
And I get the results returned in order: 1, 2, 3, 10, 100
But, what if I need to have the results returned in a specific order? When I try this:
select * FROM table WHERE id in (2, 100, 3, 1, 10);
I still get the results returned in the same order: 1, 2, 3, 10, 100
Is there a way to get the results returned in the exact order that I ask for?
(There are limitations due to the way the site is set up that won't allow me to ORDER BY using another field value)
the way you worded that I'm not sure if using ORDER BY is completely impossible or just ordering by some other field... so at the risk of submitting a useless answer, this is how you'd typically order your results in such a situation.
SELECT *
FROM table
WHERE id in (2, 100, 3, 1, 10)
ORDER BY FIELD (id, 2, 100, 3, 1, 10)
Unless you are able to do ORDER BY, there is no guaranteed way.
The sort you are getting is due to the way MySQL executes the query: it combines all range scans over the ranges defined by the IN list into a single range scan.
Usually, you force the order using one of these ways:
Create a temporary table with the value and the sorter, fill it with your values and order by the sorter:
CREATE TABLE t_values (value INT NOT NULL PRIMARY KEY, sorter INT NOT NULL)
INSERT
INTO t_values
VALUES
(2, 1),
(100, 1),
(3, 1),
(1, 1),
(10, 1);
SELECT m.*
FROM t_values v
JOIN mytable m
ON m.id = v.value
ORDER BY
sorter
Do the same with an in-place rowset:
SELECT m.*
FROM (
SELECT 2 AS value, 1 AS sorter
UNION ALL
SELECT 100 AS value, 2 AS sorter
UNION ALL
SELECT 3 AS value, 3 AS sorter
UNION ALL
SELECT 1 AS value, 4 AS sorter
UNION ALL
SELECT 10 AS value, 5 AS sorter
)
JOIN mytable m
ON m.id = v.value
ORDER BY
sorter
Use CASE clause:
SELECT *
FROM mytable m
WHERE id IN (1, 2, 3, 10, 100)
ORDER BY
CASE id
WHEN 2 THEN 1
WHEN 100 THEN 2
WHEN 3 THEN 3
WHEN 1 THEN 4
WHEN 10 THEN 5
END
You can impose an order, but only based on the value(s) of one or more columns.
To get the rows back in the order you specify in the example you would need to add a second column, called a "sortkey" whose values can be used to sort the rows in the desired sequence,
using the ORDER BY clause. In your example:
Value Sortkey
----- -------
1 4
2 1
3 3
10 5
100 2
select value FROM table where ... order by sortkey;