How to get rows having specified value in sql? - sql

I have a table like this -
id cat_id
1 1,2
2 1,3
3 5,3,11
And I want to get count of those rows which have cat_id = 1 (For Ex- in uppar case it count is 2). How can I do it ?

You can use LIKE, for example :
SELECT COUNT(*)
FROM tbl
WHERE cat_id LIKE '1,%'
if string is starting from something different ??? like 5 asked by #POHH :
SELECT COUNT(*)
FROM tbl
WHERE cat_id LIKE '%,1,%'
OR cat_id LIKE '1,%'
OR cat_id LIKE '%,1'

To get count of cat_id = 1
select count(*)
from (
select unnest(string_to_array(cat_id, ','))::int rowz
from foo ) t
where rowz = 1
To get all cat_id and it's total count
select rowz cat_id,count(*) total_count from (
select unnest(string_to_array(cat_id, ','))::int rowz
from foo ) t
group by rowz
order by cat_id

You can convert the comma separated list to an array and then use the ANY operator to search for the desired cat_id value:
select count(*)
from foo
where 1 = any (string_to_array(cat_id, ',')::int[])
But you should really consider fixing your data model. Storing comma separate lists is almost always a bad choice. If you have to de-normalize, using an array is the better choice in Postgres.

Related

Alternative to INTERSECT Given Arbitrary Number of conditions

If I have a table similar to the following:
MyIds MyValues
----- --------
1 Meat
1 Fruit
1 Veggies
2 Fruit
2 Meat
3 Meat
How do I create a query such that if I am given an arbitrary list of distinct MyValues, it will give me all the MyIds that match all of MyValues.
Example: If list of MyValues contained [Meat, Fruit, Veggies], I'd like to get MyIds of 1 back because 1 has an entry in the table for each value in MyValues.
I know that this can be done with an INTERSECT if I'm given a specific list of MyValues. But I don't know how it can be done with an arbitrary number of MyValues
You need to count the total number of instances of each MyID which satisfies the condition and that it matches to the number of value supplied in the IN clause.
SELECT MyID
FROM tableName
WHERE MyValues IN ('Meat', 'Fruit', 'Veggies')
GROUP BY MyID
HAVING COUNT(DISTINCT myVAlues) = 3
SQLFiddle Demo
A big question is how the list is being represented. The following gives one approach, representing the list in a table:
with l as (
select 'Meat' as el union all
select 'Fruit' union all
select 'Veggies'
)
select MyId
from t join
l
on t.MyValues = l.el
group by MyId
having count(distinct t.myvalues) = (select count(*) from l)

Unique results from database?

I am selecting all badge numbers from a database where category is equal to 1.
category | badge number
0 | 1
1 | 1
2 | 5
1 | 1
Sometimes the category is duplicated, is there a way to only get unique badge numbers from the database?
So above there is two 1's in category, each with badge number 1. How can I make sure the result only gives '1' rather than '1,1'
Use DISTINCT key word in the SELECT statement.
SELECT DISTINCT badge_number FROM Your_Table WHERE category = 1
Use the distinct keyword in your select.
select distinct badge_number from table_name where category = 1
Have you tried Select Distinct :
SELECT DISTINCT [badge number] from table
where Category=1
http://www.w3schools.com/sql/sql_distinct.asp
Select Distinct Badgenumber from table where Category = 1
SELECT DISTINCT BadgeNumber FROM dbo.TableName
Where Category = 1
Edited:
Ohh, there are so many posts already .... !!

oracle - getting 1 or 0 records based on the number of occurrences of a non-unique field

I have a table MYTABLE
N_REC | MYFIELD |
1 | foo |
2 | foo |
3 | bar |
where N_REC is the primary key and MYFIELD is a non-unique field.
I need to query this table on MYFIELD and extract the associated N_REC, but only if there is only one occurrence of MYFIELD; otherwise I need no records returned.
So if I go with MYFIELD='bar' I will get 3, if I go with MYFIELD='foo' I will get no records.
I went with the following query
select * from
(
select
n_rec,
( select count(*) from mytable where mycolumn=my.mycolumn ) as counter
from mytable my where mycolumn=?
)
where counter=1
While it gives me the desired result I feel like I'm running the same query twice.
Are there better ways to achieve what I'm doing?
I think that this should do what you want:
SELECT
my_field,
MAX(n_rec)
FROM
My_Table
GROUP BY
my_field
HAVING
COUNT(*) = 1
You might also try the analytic or windowing version of count(*) and compare plans to the other options:
select n_rec, my_field
from (select n_rec, my_field
, count(*) over (partition by my_field) as Counter
from myTable
where my_field = ?)
where Counter = 1

SQL query for dynamic insert row

I am having data like:
ItemCode Attribute PositionID
ITEM-000032 CHESTSIZE 1
ITEM-000032 JACKETLEN 2
ITEM-000042 CHESTSIZE 1
ITEM-000042 JACKETLEN 2
**ITEM-000049 SLACKWAIST 1**
ITEM-000071 CHESTSIZE 1
ITEM-000071 JACKETLEN 2
ITEM-000074 CHESTSIZE 1
ITEM-000074 JACKETLEN 2
In above data except ITEM-000049 others are having perfect combination. so i want to create a new row for ITEM-000049
As
ITEM-000049 -- 2
to make it perfect.
Kind regards,
Om
Sounds like for each ItemCode, you are expecting 2 records, for 2 different Attributes.
So something like this is what I think you're after. Just run the SELECT part of it first without the INSERT to check it is indeed what you're after.
INSERT YourTable (ItemCode, Attribute, PositionID)
SELECT t.ItemCode, 'SECOND ATTRIBUTE', 2
FROM
(
SELECT ItemCode
FROM YourTable
GROUP BY ItemCode
HAVING COUNT(*) = 1
) t

Select values in SQL that do not have other corresponding values except those that i search for

I have a table in my database:
Name | Element
1 2
1 3
4 2
4 3
4 5
I need to make a query that for a number of arguments will select the value of Name that has on the right side these and only these values.
E.g.:
arguments are 2 and 3, the query should return only 1 and not 4 (because 4 also has 5). For arguments 2,3,5 it should return 4.
My query looks like this:
SELECT name FROM aggregations WHERE (element=2 and name in (select name from aggregations where element=3))
What do i have to add to this query to make it not return 4?
A simple way to do it:
SELECT name
FROM aggregations
WHERE element IN (2,3)
GROUP BY name
HAVING COUNT(element) = 2
If you want to add more, you'll need to change both the IN (2,3) part and the HAVING part:
SELECT name
FROM aggregations
WHERE element IN (2,3,5)
GROUP BY name
HAVING COUNT(element) = 3
A more robust way would be to check for everything that isn't not in your set:
SELECT name
FROM aggregations
WHERE NOT EXISTS (
SELECT DISTINCT a.element
FROM aggregations a
WHERE a.element NOT IN (2,3,5)
AND a.name = aggregations.name
)
GROUP BY name
HAVING COUNT(element) = 3
It's not very efficient, though.
Create a temporary table, fill it with your values and query like this:
SELECT name
FROM (
SELECT DISTINCT name
FROM aggregations
) n
WHERE NOT EXISTS
(
SELECT 1
FROM (
SELECT element
FROM aggregations aii
WHERE aii.name = n.name
) ai
FULL OUTER JOIN
temptable tt
ON tt.element = ai.element
WHERE ai.element IS NULL OR tt.element IS NULL
)
This is more efficient than using COUNT(*), since it will stop checking a name as soon as it finds the first row that doesn't have a match (either in aggregations or in temptable)
This isn't tested, but usually I would do this with a query in my where clause for a small amount of data. Note that this is not efficient for large record counts.
SELECT ag1.Name FROM aggregations ag1
WHERE ag1.Element IN (2,3)
AND 0 = (select COUNT(ag2.Name)
FROM aggregatsions ag2
WHERE ag1.Name = ag2.Name
AND ag2.Element NOT IN (2,3)
)
GROUP BY ag1.name;
This says "Give me all of the names that have the elements I want, but have no records with elements I don't want"