Pointid
Productid
5
24
6
24
6
25
6
26
7
24
7
25
7
26
7
27
For the query:
select distinct pointid
from mytable
where productid in (24,25,26)
The result is: 5,6,7
But I want only 6.
No more No less..
How can I do it?
The main goal is to find those pointid where their productid are EXACTLY 24, 25, 26. Importantly: no more, no less.
In essence, you are requiring two distinct conditions:
That the pointid contains ALL of the following productids; 24, 25, 26, and,
That the pointid does not contain any other productid.
Both conditions can be addressed with a having clause.
You make sure that it contains all of the productids. As there are 3, you want the count of the productids that match 24, 25, 26, to be exactly 3: COUNT(DISTINCT CASE WHEN productid in (24, 25, 26) THEN productid END) = 3.
You want it to contain no other productid. So you make sure that the total value of distinct productids is 3: COUNT(DISTINCT productid) = 3.
The following query puts it all together:
SELECT pointid
FROM mytable
GROUP BY pointid
HAVING COUNT(DISTINCT CASE WHEN productid in (24, 25, 26) THEN productid END) = 3
AND COUNT(DISTINCT productid) = 3
;
If you wanted to do something similar with different conditions (as you mentioned in your comments):
Replace 24,25,26, for the productids that you want to check.
Replace 3 for the number of productids that you are checking.
Use aggregation and having:
select pointid
from mytable
group by pointid
having sum(case when productid in (24, 25, 26) then 1 else 0 end) = 3 and
count(*) = 3;
Here is a db<>fiddle.
If you want to filter the rows where productid is in(24,25,26) and pointid count is maximum. Then try this
SELECT pointid FROM mytable
GROUP BY pointid HAVING productid in(24,25,26)
ORDER BY COUNT(pointid) DESC LIMIT 1;
Related
My table contains 113 people.
48 of them are 20 years old. Now I am just selecting all people like
select * from persons
this will get me all persons, but 20 yr old are not the first 48 people.
I need the 20 yr old to be first 48 in 113 results.
something like
20 year ols ( 48 of them ), after that ..... all the rest in the table
How can I query this using PostgreSQL.
EDIT : there are age less than 20 too. after getting the first 48 , 20 yr olds, I dont care rest of the order I am getting the 48 to 113 people.
Just use order by :
select *
from persons
order by age
You can use asc or desc but because default is asc you do not need to put it in your example.
select *
from persons
order by age desc
After the comment from OP here is the new code(I do not know why but my firs assumption was that the value 20 is the lowest possible value... bad assumption):
select *
from persons
order by case when age = 20 then 1 else 2 end
OR
select *
from persons
order by (age = 20) desc
Here is a demo
If 20 is not your minimum age, you can use the CASE statement inside the ORDER BY clause, like this:
SELECT
*
FROM
persons
ORDER BY
CASE WHEN age = 20 THEN 0
ELSE 1
END ASC
I have a SQL question from one of the well known IT company couple month ago when they were interviewing me, and I never got it figured out.
An order can have multiple lines - For ex., if a customer ordered cookies,
chocolates, and bread, this would count as 3 lines in one order. The question
is to find the number of orders in each line count. The output of this query
would be something like 100 orders had 1 line, 70 orders had 2 lines, 30 had 3
lines, and so on. This table has two columns - order_id and line_id
Sample Data:
order_id line_id
1 cookies
1 chocolates
1 bread
2 cookies
2 bread
3 chocolates
3 cookies
4 milk
desired output:
orders line
1 1
2 2
1 3
So generally speaking, we have a very large data set, and the line_id per order_id can be ranging from 1 to infinite(Theoretically speaking).
The desired output for the general case is:
orders line
100 1
70 2
30 3
etc..
How can I write a query to find the total number of orders per line count=1,2,3... etc
My thought on this problem is to first subquery the count of line_id per order_id.
And then select the subquery along with a list of values as the second column ranging from 1 to max(lines_id per order)
Test Data:
create table data
(
order_id int,
line_id char(50)
);
insert into data
values(1, 'cookies'),
(1, 'chocolates'),
(1, 'bread'),
(2, 'bread'),
(2, 'cookies'),
(3, 'chocolates'),
(3, 'cookies'),
(4, 'milk');
Since order_id=1 has 3 lines,
order_id=2 has 2 lines,
order_id=3 has 2 lines,
order_id=4 has 1 line.
Thus it yield our solution:
orders line
1 1
2 2
1 3
This is because both order_id = 2 and 3 has 2 lines. So it would mean 2 orders has line = 2.
So far, I have:
select lines,
sum(case when orders_per_line = '1' then 1 else 0),
sum(case when orders_per_line = '2' then 1 else 0),
sum(case when orders_per_line = '3' then 1 else 0)
from(
select lines, order_id, count(*) as orders_per_line from data
where lines in ('1, '2', '3')
group by order_id, lines
)
group by lines
My query is wrong, as I only want 2 columns, and also creating a sequence of numbers ranging from 1 to max(lines per order) is also wrong.
Any suggestions?
Thanks in advance!
Try this:
Select Count(*) as Orders, Lines from (
Select order_id, Count(*) as Lines from data group by order_id
)query group by Lines
For exmaple, look at this sqlfiddle
Try This:
with a AS
(
SELECT
COUNT(order_id) AS Orders
FROM
Table_1
GROUP BY
Order_Id
)
SELECT
Orders,
COUNT(*) AS line
FROM
a
GROUP BY Orders
Basically, it just count how many times the order_id are repeated:
SELECT order_id, count(order_id) FROM data GROUP BY order_id
I have a table with
cID, side, row, column
with some data of
24, 1, 10, 5
25, 1, 12, 6
24, 2, 18, 3
and so on. Now I want these data to be show in the form of:
cID=24
side 1 2
row 10 18
column 5 3
cID=25
side 2
row 12
column 6
The cID is filtered in the query so the output will be the 3 rows (side, row, column) and the data of them of a specific cID.
Is that possible with MsAccess Query/SQL and how?
Thanks!
Something on these lines:
TRANSFORM First(q.rvalue) AS firstofrow
SELECT q.rhead
FROM (SELECT cid,
side,
row AS rvalue,
"row" AS rhead
FROM atable
UNION ALL
SELECT cid,
side,
column AS rvalue,
"column" AS rhead
FROM atable) AS q
WHERE q.cid = 24
GROUP BY q.rhead
PIVOT q.side;
for a table such as:
employeeID | groupCode
1 red111
2 red111
3 blu123
4 blu456
5 red553
6 blu423
7 blu341
how can I count the number of employeeIDs that are in parent groups (such as red or blu, but there are many more groups in the real table) that have a total number of group members greater than 2 (so all those with blu in this particular example) excluding themselves.
To expand: groupCode consists of a parent group (three letters), followed by some numbers for the subgroup.
using a self-join, or at least without using a group by statement.
So far I have:
SELECT T1.employeeID
FROM TABLE T1, TABLE T2
WHERE T1.groupCode <> T2.groupCode
AND SUBSTR(T1.groupCode, 1, 3) = SUBSTR(T2.gorupCode, 1, 3);
but that doesn't do much for me...
Add an index on the first 3 characters of EMPLOYEE.
Then try this one:
SELECT ed.e3
, COUNT(*)
FROM EMPLOYEE e
JOIN
( SELECT DISTINCT
SUBSTR(groupCode, 1, 3) AS e3
FROM EMPLOYEE
) ed
ON e.groupCode LIKE CONCAT(ed.e3, '%')
GROUP BY ed.e3
HAVING COUNT(*) >= 3 --- or whatever is wanted
What about
SELECT substring(empshirtno, 1, 3),
Count(SELECT 1 from myTable as myTable2
WHERE substring(mytable.empshirtno, 1, 3) = substring(mytable2.empshirtno, 1, 3))
FROM MyTable
GROUP BY substring(mytable2.empshirtno, 1, 3)
maybe counting from a subquery is speedier with an index
I need to display a list of records from a database table ordered by some numeric column. The table looks like this:
CREATE TABLE items (
position int NOT NULL,
name varchar(100) NOT NULL,
);
INSERT INTO items (position, name) VALUE
(1, 'first'),
(5, 'second'),
(8, 'third'),
(9, 'fourth'),
(15, 'fifth'),
(20, 'sixth');
Now, the order of the list should change according to a parameter provided by the user. This parameter specifies which record comes first like this:
position = 0
order should be = 1, 5, 8, 9, 15, 20
position = 1
order should be = 20, 1, 5, 8, 9, 15
position = 2
order should be = 15, 20, 1, 5, 8, 9
In other words the last record becomes the first and so on. Can you think of a way to do this in SQL?
I'm using MySQL but an example in any SQL database will do.
Thanks
See how this works for you. Uses generic SQL so it should be valid for MySql (untested) as well.
DECLARE #user_sort INTEGER
SET #user_sort = 0
SELECT position, name FROM
(
SELECT I1.position, I1.name, COUNT(*) AS rownumber, (SELECT COUNT(*) FROM items) AS maxrows
FROM items I1, items I2
WHERE I2.position <= I1.position
GROUP BY I1.position, I1.name
) Q1
ORDER BY
CASE WHEN maxrows - rownumber < (#user_sort % maxrows) THEN 1 ELSE 2 END, position
Note:
* If the user provided sort index is greater than the row count, the value will wrap to within the valid range. To remove this functionality, remove the "% maxrows" from the ORDER BY.
Results:
SET #user_sort = 0
position name
1 first
5 second
8 third
9 fourth
15 fifth
20 sixth
SET #user_sort = 1
position name
20 sixth
1 first
5 second
8 third
9 fourth
15 fifth
SET #user_sort = 2
position name
15 fifth
20 sixth
1 first
5 second
8 third
9 fourth
SET #user_sort = 9
9 fourth
15 fifth
20 sixth
1 first
5 second
8 third
Are you sure you want to do this in SQL?
To me, this sounds like you should load the results in a dataset of some sort, and then either re-order them as you want, or position the starting point at the correct position.
Possibly using a linked list.
ORDER BY (FIELD(position, 1, 5, 8, 9, 15, 20) + parameter) % 7
Edit: To make the peanut gallery happy, the general solution is:
ORDER BY (SELECT ix + parameter - 1 FROM (SELECT i.position, #ix := #ix + 1 AS ix FROM (SELECT #ix := 0) AS n, items AS i ORDER BY position) AS s WHERE s.position = items.position) % (SELECT COUNT(*) FROM items)
I'm riffing on beach's solution here, but eliminating the self-join and only selecting from the items table twice (and using Oracle syntax):
select
i.position
, i.name
from(
select
items.*
, ( SELECT COUNT(*) FROM items ) AS maxrows
from items
order by position
) i
order by
case
when rownum > maxrows - 2 -- NOTE: change "2" to your "position" variable
then 1 - 1 / rownum -- pseudo-rownum < 1, still ascending
else
rownum
end
;
If it's a set list that you know the number of items you could do something like:
SELECT *
FROM Items
ORDER BY CASE WHEN Position >= Position THEN POSITION ELSE Position+1000 END
But its really ugly.
This really is not an ideal thing to be doing in SQL.
I have solution, but with large tables it will be slow.
DECLARE #iOrder INT
SET #iOrder = 4
SELECT abc.position,abc.name FROM
(
SELECT position,name,ROW_NUMBER() OVER (ORDER BY position) AS rownum
FROM items
) abc
WHERE abc.rownum >= #iOrder
UNION ALL
SELECT def.position, def.name FROM
(
SELECT position,name,ROW_NUMBER() OVER (ORDER BY position) AS rownum
FROM items
) def
WHERE def.rownum < #iOrder
Note that the use of UNION (Without the all) will reorder the results as it'll be looking for duplicates
As per John's comment, but with LIMIT syntax instead (ROW_NUMBER/OVER doesn't work in MySQL and besides LIMIT is much easier to read):
(
SELECT position, name FROM items
ORDER BY position
LIMIT #offset, #bignum
) UNION ALL (
SELECT position, name FROM items
ORDER BY position
LIMIT #offset
)
Where #bignum is an arbitrary number higher than any number of results you might have.
I'm still not wholly convinced this will in practice be faster than rearranging the list on the web server... would depend exactly how you were dealing with the result set and how big it was, I suppose. But at least it avoids the self-cross-join involved in beach's clever approach.