I have a select statement in SQL. The select statement is selecting a licenseNo and a LicenseID. Basically, I want it to return the LicenseNo depending on which LicenseTypeID it is.
For example, I want it to return the LicenseNo if the LicenseTypeID = 6 first, then if there is no ID that equals 6, return the LicenseNo where the LicenseTypeID = 5 and so on.
Right now, I have a join that is causing multiple LicenseNos to be returned because there are multiple LicenseTypeIDs. I only want it to return the LicenseNo and row in which the ID of 6 takes precedence, then 5, then 4 and so on. It looks something like this right now:
Select a.Name,
a.addressNo,
b.LicenseNo,
LicenseTypeID
from addressbook a
join licenses b
on a.addressNo = b.addressNo
Returns
111 CompanyA 1234 6
111 CompanyA 2222 4
So I only want it to return the first row, and if that ID doesnt exist (6) I want it to return the second row of 4.
You need a subselect to determine the maximum licence number for each address:
select
a.name,
a.addressno,
l.licenseno,
l.licensetypeid
from addressbook a
join licenses l on l.addressno = a.addressno
where l.licenseno =
(
select max(licenseno)
from licenses
where licenses.addressno = a.addressno
);
Try this.
SELECT * FROM
(SELECT ROW_NUMBER() OVER
(PARTITION BY l.licenseno ORDER BY l.licenseno DESC) NO,
a.Name,
a.addressNo,
b.LicenseNo,
LicenseTypeID
from addressbook a
join licenses b
on a.addressNo = b.addressNo) AS t WHERE no = 1
Related
I have the following table which contains ID's and UserId's.
ID UserID
1111 11
1111 300
1111 51
1122 11
1122 22
1122 3333
1122 45
I'm trying to count the distinct number of 'IDs' so that I get a total, but I also need to get a total of ID's that have also seen the that particular ID as well... To get the ID's, I've had to perform a subquery within another table to get ID's, I then pass this into the main query... Now I just want the results to be displayed as follows.
So I get a Total No for ID and a Total Number for Users ID - Also would like to add another column to get average as well for each ID
TotalID Total_UserID Average
2 7 3.5
If Possible I would also like to get an average as well, but not sure how to calculate that. So I would need to count all the 'UserID's for an ID add them altogether and then find the AVG. (Any Advice on that caluclation would be appreciated.)
Current Query.
SELECT DISTINCT(a.ID)
,COUNT(b.UserID)
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
GROUP BY a.ID
Which then Lists all the IDs and COUNT's all the USERID.. I would like a total of both columns. I've tried warpping the query in a
SELECT COUNT(*) FROM (
but this only counts the ID's which is great, but how do I count the USERID column as well
You seem to want this:
SELECT COUNT(DISTINCT a.ID), COUNT(b.UserID),
COUNT(b.UserID) * 1.0 / COUNT(DISTINCT a.ID)
FROM a INNER JOIN
b
ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999);
Note: DISTINCT is not a function. It applies to the whole row, so it is misleading to put an expression in parentheses after it.
Also, the GROUP BY is unnecessary.
The 1.0 is because SQL Server does integer arithmetic and this is a simple way to convert a number to a decimal form.
You can use
SELECT COUNT(DISTINCT a.ID) ...
to count all distinct values
Read details here
I believe you want this:
select TotalID,
Total_UserID,
sum(Total_UserID+TotalID) as Total,
Total_UserID/TotalID as Average
from (
SELECT (DISTINCT a.ID) as TotalID
,COUNT(b.UserID) as Total_UserID
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
) x
Probably the wrong title, but I can't summarise what I'm trying to do nicely. Which is probably why my googling hasn't helped.
I have a list of Discounts, and a list of TeamExclusiveDiscounts (DiscountId, TeamId)
I call a stored procedure passing in #TeamID (int).
What I want is all Discounts except if they're in TeamExclusiveDiscounts and don't have TeamID matching #TeamId.
So the data is something like
Table Discount:
DiscountID Name
-----------------------
1 Test 1
2 Test 2
3 Test 3
4 Test 4
5 Test 5
Table TeamExclusiveDiscount:
DiscountID TeamID
-----------------------
1 10
2 10
2 4
3 8
Expected results:
searching for TeamID = 10 I should get discounts 1,2,4,5
searching for TeamID = 5 I should get discounts 4, 5
searching for TeamID = 8 I should get discounts 3, 4, 5
I've tried a variety of joins, or trying to update a temp table to set whether the discount is allowed or not, but I just can't seem to get my head around this issue.
So I'm after the T-SQL for my stored procedure that will select the correct discounts (SQL Server). Thanks!
SELECT D.DiscountID FROM Discounts D
LEFT JOIN TeamExclusiveDiscount T
ON D.DiscountID=T.DiscountID
WHERE T.TeamID=#TeamID OR T.TeamID IS NULL
SQLFIDDLE for TEST
Can you try this - it only selects records where there is a teamdiscount record with the team or no teamdiscount record at all.
SELECT * FROM Discounts D
WHERE
EXISTS (
SELECT 1
FROM TeamExclusiveDiscount T
WHERE T.DiscountID = D.DiscountID
AND TeamID = #TeamID
)
OR
NOT EXISTS (
SELECT 1
FROM TeamExclusiveDiscount T
WHERE T.DiscountID = D.DiscountID
)
I like to translate the English description directly into SQL (atleast as a first pass):
"All Discounts except if they're in TeamExclusiveDiscounts and don't have TeamID matching #TeamId."
SELECT *
FROM Discounts D -- All Discounts
WHERE D.DiscountID NOT IN -- except if they're in TeamExclusiveDiscounts
(SELECT T.DiscountID
FROM TeamExclusiveDiscount T
WHERE T.DiscountID NOT IN -- and don't have TeamID matching #TeamId.
(SELECT Match.DiscountID
FROM TeamExclusiveDiscount Match
WHERE Match.TeamID = #TeamID)
)
STEP 1
Select data1,name,phone,address from dummyTable limit 4;
From above query, I will get the following result for example:
data1 | name | phone | address
fgh | hjk | 567...| CA
ghjkk | jkjii| 555...| NY
Now, after having the above result I am suppose to match data1 records that I got from above query to existing another table in a database called existingTable which has a same column called data1 in it. If the result above gives data1 value as 'fgh' so I take that 'fgh' and compare with that existingtable column called data1.
STEP 2
Next, after I am finished comparing, I need to apply some condition as follows:
if((results.data1.value).equals(existingTable.data1.value))
then count --
else
count++
So by above condition I am trying to explain, that if the value I got from the result is matched then I do count decrement by 1 and if not then count is incremented by 1.
Summary
I basically wanted to achieve this in one single query, is it possible using PostgreSQL?
I think you can translate that to a simple query:
SELECT d.data1, d.name, d.phone, d.address
, count(*) - 2 * count(e.data1)
FROM (
SELECT data1, name, phone, address
FROM dummytable
-- ORDER BY ???
LIMIT 4
) d
LEFT JOIN existingtable e USING (data1)
GROUP BY d.data1, d.name, d.phone, d.address;
The major ingredient is the LEFT [OUTER] JOIN. Follow the link to the manual.
count(*) counts all rows from dummytable.
count(e.data1) only counts rows from existingtable where a matching data1 exists (count() does not count NULL values). I subtract that twice to match your formula.
About ORDER BY: There is no natural order in a database table. You need to order by something to get predictable results.
If there can be duplicates in existingtable but you want to count every distinct data1 only once, eliminate dupes before you join or use an EXISTS semi-join:
SELECT data1, name, phone, address
, count(*) - 2 * count(EXISTS (
SELECT 1 FROM existingtable e
WHERE e.data1 = d.data1) OR NULL)
FROM (
SELECT data1, name, phone, address
FROM dummytable
-- ORDER BY ???
LIMIT 4
) d
GROUP BY data1, name, phone, address;
The last count works because (TRUE OR NULL) IS TRUE, but (FALSE OR NULL) IS NULL.
database table like this
============================
= suburb_id | value
= 1 | 2
= 1 | 3
= 2 | 4
= 3 | 5
query is
SELECT COUNT(suburb_id) AS total, suburb_id
FROM suburbs
where suburb_id IN (1,2,3,4)
GROUP BY suburb_id
however, while I run this query, it doesn't give COUNT(suburb_id) = 0 when suburb_id = 0
because in suburbs table, there is no suburb_id 4, I want this query to return 0 for suburb_id = 4, like
============================
= total | suburb_id
= 2 | 1
= 1 | 2
= 1 | 3
= 0 | 4
A GROUP BY needs rows to work with, so if you have no rows for a certain category, you are not going to get the count. Think of the where clause as limiting down the source rows before they are grouped together. The where clause is not providing a list of categories to group by.
What you could do is write a query to select the categories (suburbs) then do the count in a subquery. (I'm not sure what MySQL's support for this is like)
Something like:
SELECT
s.suburb_id,
(select count(*) from suburb_data d where d.suburb_id = s.suburb_id) as total
FROM
suburb_table s
WHERE
s.suburb_id in (1,2,3,4)
(MSSQL, apologies)
This:
SELECT id, COUNT(suburb_id)
FROM (
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 3 AS id
UNION ALL
SELECT 4 AS id
) ids
LEFT JOIN
suburbs s
ON s.suburb_id = ids.id
GROUP BY
id
or this:
SELECT id,
(
SELECT COUNT(*)
FROM suburb
WHERE suburb_id = id
)
FROM (
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 3 AS id
UNION ALL
SELECT 4 AS id
) ids
This article compares performance of the two approaches:
Aggregates: subqueries vs. GROUP BY
, though it does not matter much in your case, as you are querying only 4 records.
Query:
select case
when total is null then 0
else total
end as total_with_zeroes,
suburb_id
from (SELECT COUNT(suburb_id) AS total, suburb_id
FROM suburbs
where suburb_id IN (1,2,3,4)
GROUP BY suburb_id) as dt
#geofftnz's solution works great if all conditions are simple like in this case. But I just had to solve a similar problem to generate a report where each column in the report is a different query. When you need to combine results from several select statements, then something like this might work.
You may have to programmatically create this query. Using left joins allows the query to return rows even if there are no matches to suburb_id with a given id. If your db supports it (which most do), you can use IFNULL to replace null with 0:
select IFNULL(a.count,0), IFNULL(b.count,0), IFNULL(c.count,0), IFNULL(d.count,0)
from (select count(suburb_id) as count from suburbs where id=1 group by suburb_id) a,
left join (select count(suburb_id) as count from suburbs where id=2 group by suburb_id) b on a.suburb_id=b.suburb_id
left join (select count(suburb_id) as count from suburbs where id=3 group by suburb_id) c on a.suburb_id=c.suburb_id
left join (select count(suburb_id) as count from suburbs where id=4 group by suburb_id) d on a.suburb_id=d.suburb_id;
The nice thing about this is that (if needed) each "left join" can use slightly different (possibly fairly complex) query.
Disclaimer: for large data sets, this type of query might have not perform very well (I don't write enough sql to know without investigating further), but at least it should give useful results ;-)
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"