Select distinct of rows and show count of each value - sql

I'm trying to select a distinct selection of [AssetManager].[AssetType] with a count of how many times the Id of an Asset Type is being referenced from table [AssetManager].[Asset]. Please see below for an example:
+-----------+-------------+
| Type Name | Asset Count |
+-----------+-------------+
| Phone | 5 |
| Desktop | 12 |
| Laptop | 22 |
+-----------+-------------+
However, the query I'm trying isn't working at all, the furthest I've got is selecting Asset titles with an inner join of their Type name (I'm not great at SQL...). Please see below for my current Query:
SELECT
[Asset].[Title] AssetTitle,
[AssetType].[Title] TypeTitle
FROM
[AssetManager].[Asset]
INNER JOIN
[AssetManager].[AssetType]
ON
[Asset].[AssetType_Id] = [AssetType].[Id]

As the comments said, all you needed to do is add a GROUP BY correctly:
SELECT
[AssetType].[Title] TypeTitle
, COUNT(*) [Asset Count]
FROM [AssetManager].[Asset]
INNER JOIN [AssetManager].[AssetType]
ON [Asset].[AssetType_Id] = [AssetType].[Id]
GROUP BY [AssetType].[Title]

Use OUTER APPLY to get reference count from [AssetManager].[Asset] table
SELECT
DISTINCT [AssetType].[Title] TypeTitle,
M.TypeCount
FROM
[AssetManager].[AssetType]
OUTER APPLY(
SELECT COUNT([Asset].[AssetType_Id]) AS TypeCount
FROM [AssetManager].[Asset]
WHERE [Asset].[AssetType_Id] = [AssetType].[Id]
)M

Related

How can I write a SQL join subquery to get the newest record for a relationship?

I have a SQL query for a Lansweeper report and I want to bring in the owner relationship, but I want to cover for cases when two relationships of the same type are written. I would like to return the most recently modified relationship.
SELECT tblAssets.AssetID,
tblAssetCustom.Serialnumber AS [Serial Number],
UPPER(tblAssets.AssetName) AS Name,
tblADusers.UPN AS [User]
FROM tblAssets
LEFT OUTER JOIN tblAssetCustom ON tblAssets.AssetID = tblAssetCustom.AssetID
LEFT OUTER JOIN tblAssetUserRelations ON tblAssets.AssetID = tblAssetUserRelations.AssetID
AND tblAssetUserRelations.Type = 1
LEFT OUTER JOIN tblADusers ON tblAssetUserRelations.Username = tblADusers.Username
WHERE (tblAssets.Assettype = - 1)
ORDER BY Name
Some records in this report are duplicated because they are being included. These assetUserRelations are also of Type = 1 but can be filtered by getting the most recent like below.
SELECT TOP (1) RelationID FROM tblAssetUserRelations order by Lastchanged desc
How can I add in a subquery that returns a user's UPN if there is a relationship of type=1 and get the most recent for any found relationships for the device?
I tried building a subquery join like this, but it returned only 1 user UPN for the entire query.
Left Join (Select *
From tblAssetUserRelations
Where tblAssetUserRelations.RelationID In (Select Top (1)
tblAssetUserRelations.RelationID
From tblAssetUserRelations Order By tblAssetUserRelations.Lastchanged
Desc)) As recentUserRelations On tblAssets.AssetID = recentUserRelations.AssetID
In my code from my top query I get a sample output like this because there are two entries in the tblAssetUserRelations table that have columns with tblAssetUserRelations.Type = 1 and tblAssetUserRelations.AssetID = 3730, but only one has a newer tblAssetUserRelations.Lastchanged value
| AssetID | Serial Number | Name | User |
| :-----: | :-----------: | :--------: | :--------------: |
|3730 |984621346we |harolddv-lpt|harold#example.com|
|3730 |984621346we |harolddv-lpt|thomas#example.com|
The expected output should look like this
| AssetID | Serial Number | Name | User |
| :-----: | :-----------: | :--------: | :--------------: |
|3730 |984621346we |harolddv-lpt|harold#example.com|

How to join my tables with ID's that do not match

I have these tables:
payments
| id | src_account | dest_account | payment_value |
+----+-------------+--------------+---------------+
| 1 | xxxxxxxxxxx | yyyyyyyyyyyy | 200 |
client_account
| client_id | account_id |
+-----------+-------------+
| 3 | xxxxxxxxxxx |
| 4 | yyyyyyyyyyy |
client
| id | firstname | lastname |
+----+-----------+------------+
| 3 | Sofia | Lenhark |
| 4 | Mark | Davoreski |
Now I need to select the following fields in a SQL Query:
Source Firstname
Source Lastname
Destination Firstname
Destination Lastname
Payment Value
I have tried the following:
SELECT
srcClientDetails.firstname,
srcClientDetails.lastname,
destClientDetails.firstname,
destClientDetails.lastname,
Payments.payment_value
FROM
dbo.payment AS Payments
LEFT JOIN dbo.client_account AS srcClientAccount ON Payments.src_account = srcClientAccount.account_id
LEFT JOIN dbo.client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
LEFT JOIN dbo.client_account AS destClientAccount ON Payments.dest_account = destClientAccount.account_id
LEFT JOIN dbo.client AS destClientDetails ON destClientAccount.client_id = destClientDetails.id
But this is returning only the payment value, without any other data.
Why aren't the other desired fields being returned?
Suggestions
(1) Try it in INNER JOIN
To check that the JOIN is correct (Values are equal),first test the query using INNER JOIN
SELECT *
FROM dbo.payment AS Payments
INNER JOIN dbo.client_account AS srcClientAccount ON Payments.src_account =
srcClientAccount.account_id
and check if it returns values or not, then add another table:
SELECT *
FROM dbo.payment AS Payments
INNER JOIN dbo.client_account AS srcClientAccount ON Payments.src_account =
srcClientAccount.account_id
INNER JOIN dbo.client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
And so on... This may leads you to the issue
(2) Account id difference due to collation or additional spaces
I think this will lead you to the problem, it may be caused due to a case sensitive collation or length sensitive or additional spaces. To diagnose this issue, you can also try converting both columns to same case and length and Trim additional spaces.
ON LTRIM(RTRIM(UPPER(CAST(Payments.src_account as varchar(50))))) = LTRIM(RTRIM(UPPER(CAST(srcClientAccount.account_id as varchar(50)))))
If this fixes the problem than it is better to edit the data (adding relations or constraints) rather than using this functions in the Join because it decrease the performance and doesn't use indexes.
(3) Create relations between tables
From the question it seems that there is no relation between columns, create the relations so values are constrained.
Your logic was right, just the [client_account].account_id was 1 'y' short for matching, or Payments.dest_account needs 1 less 'y'.
For example, you can see here I added 1 'y' to the [client_account].account_id and your query now returns the correct information:
WITH Payments AS (
SELECT '1' as id,
'xxxxxxxxxxx' as src_account,
'yyyyyyyyyyyy' as dest_account,
'200' as payment_value),
client_account AS (
SELECT '3' as client_id,
'xxxxxxxxxxx' as account_id
UNION ALL
SELECT '4' as client_id,
'yyyyyyyyyyyy' as 'account_id'), --added a 'y' here
client AS (
SELECT '3' as id,
'Sofia' as firstname,
'Lenhark' as lastname
UNION ALL
SELECT '4' as id,
'Mark' as firstname,
'Davoreski' as lastname)
SELECT
srcClientDetails.firstname,
srcClientDetails.lastname,
destClientDetails.firstname,
destClientDetails.lastname,
Payments.payment_value
FROM
payments AS Payments
LEFT JOIN client_account AS srcClientAccount ON Payments.src_account = srcClientAccount.account_id
LEFT JOIN client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
LEFT JOIN client_account AS destClientAccount ON Payments.dest_account = destClientAccount.account_id
LEFT JOIN client AS destClientDetails ON destClientAccount.client_id = destClientDetails.id
Try it here

Getting results from two different tables using a join

Let's say I have the following tables:
+-------------------------------------------+
| t_classroom |
+-------------------------------------------+
| PK | id |
| | admin_user_id |
| | name |
| | students |
+-------------------------------------------+
+-------------------------------------------+
| t_shared |
+-------------------------------------------+
| | admin_user_id |
| | classroom_id |
| | expiry |
+-------------------------------------------+
I want to write a query that will pull all classrooms that an admin_user_id has access to. In essence, I want a union of classroom rows when I search by admin_user_id in the t_classroom table as well as classroom rows when I search by admin_user_id in the t_shared table. I made the following attempt:
SELECT
id,
admin_user_id,
name,
students
FROM
t_classroom
WHERE
admin_user_id = 1
UNION ALL
SELECT
c.id,
c.admin_user_id,
c.name,
students
FROM
t_classroom c
INNER JOIN t_shared s
ON c.id = s.classroom_id
WHERE
admin_user_id = 1
Does the above look correct? Is there anything more efficient/cleaner?
Depending on how much data you have you could probably get away with just using an IN clause to look at the other table.
SELECT
c.id,
c.admin_user_id,
c.name,
c.students
FROM
t_classroom c
WHERE
c.admin_user_id = 1
OR c.id IN ( select s.classroom_id from t_shared s where s.admin_user_id = 1 )
Your union wont work because you're left-joining to the t_shared table and checking only the classroom admin user.
If you join the shared room you would also end up with duplicates and would need to distinct the result too.
Edit:
Because of the large number of rows it might be better to use an exists check on the 2nd table.
SELECT
c.id,
c.admin_user_id,
c.name,
c.students
FROM
t_classroom c
WHERE
c.admin_user_id = 1
OR EXISTS ( select 1 from t_shared s where s.classroom_id = c.id AND s.admin_user_id = 1 )
Your solution is fundamentally fine, the only two problems I can detect when eyeballing your query are:
You need to write s.admin_user_id instead of admin_user_id in the last line to avoid an error message, because there is a column of that name in both tables. Best practice is to always qualify column names with the table names.
You might want to use UNION instead of UNION ALL if you want to avoid a duplicate result row in the case that both tables have admin_user_id = 1 for the same classroom.

INNER JOIN Need to use column value twice in results

I've put in the requisite 2+ hours of digging and not getting an answer.
I'd like to merge 3 SQL tables, where Table A and B share a column in common, and Table B and C share a column in common--Tables A and C do not.
For example:
Table A - entity_list
entity_id | entity_name | Other, irrelevant columns
Example:
1 | Microsoft |
2 | Google |
Table B - transaction_history
transaction_id | purchasing_entity | supplying_entity | other, irrelevant columns
Example:
1 | 2 | 1
Table C - transaction_details
transactional_id | amount_of_purchase | Other, irrelevant columns
1 | 5000000 |
Using INNER JOIN, I've been able to get a result where I can link entity_name to either purchasing_entity or supplying_entity. And then, in the results, rather than seeing the entity_id, I get the entity name. But I want to substitute the entity name for both purchasing and supplying entity.
My ideal results would look like this:
1 [transaction ID] | Microsoft | Google | 5000000
The closes I've come is:
1 [transaction ID] | Microsoft | 2 [Supplying Entity] | 5000000
To get there, I've done:
SELECT transaction_history.transaction_id,
entity_list.entity_name,
transaction_history.supplying_entity,
transaction_details.amount_of_purchase
FROM transaction.history
INNER JOIN entity_list
ON transaction_history.purchasing_entity=entity_list.entity.id
INNER JOIN
ON transaction_history.transaction_id=transaction_details.transaction_id
I can't get entity_name to feed to both purchasing_entity and supplying_entity.
Here is the query:
SELECT h.transaction_id, h.purchasing_entity, purchaser.entity_name, h.supplying_entity, supplier.entity_name, d.amount_of_purchase
FROM transaction_history h
INNER JOIN transaction_details d
ON h.transaction_id = d.transaction_id
INNER JOIN entity_list purchaser
ON h.purchasing_entity = purchaser.entity_id
INNER JOIN entity_list supplier
ON h.supplying_entity = supplier.entity_id

Access query to grab +5 or more duplicates

i have a little problem with an Access query ( dont ask me why but i cannot use a true SGBD but Access )
i have a huge table with like 920k records
i have to loop through all those data and grab the ref that occur more than 5 time on the same date
table = myTable
--------------------------------------------------------------
| id | ref | date | C_ERR_ANO |
--------------------------------------------|-----------------
| 1 | A12345678 | 2012/02/24 | A 4565 |
| 2 | D52245708 | 2011/05/02 | E 5246 |
| ... | ......... | ..../../.. | . .... |
--------------------------------------------------------------
so to resume it a bit, i have like 900000+ records
there is duplicates on the SAME DATE ( oh by the way there is another collumn i forgot to add that have C_ERR_ANO as name)
so i have to loop through all those row, grab each ref based on date AND errorNumber
and if there is MORE than 5 time with the same errorNumber i have to grab them and display it in the result
i ended up using this query:
SELECT DISTINCT Centre.REFERENCE, Centre.DATESE, Centre.C_ERR_ANO
FROM Centre INNER JOIN (SELECT
Centre.[REFERENCE],
COUNT(*) AS `toto`,
Centre.DATESE
FROM Centre
GROUP BY REFERENCE
HAVING COUNT(*) > 5) AS Centre_1
ON Centre.REFERENCE = Centre_1.REFERENCE
AND Centre.DATESE <> Centre_1.DATESE;
but this query isent good
i tried then
SELECT DATESE, REFERENCE, C_ERR_ANO, COUNT(REFERENCE) AS TOTAL
FROM (
SELECT *
FROM Centre
WHERE (((Centre.[REFERENCE]) NOT IN (SELECT [REFERENCE]
FROM [Centre] AS Tmp
GROUP BY [REFERENCE],[DATESE],[C_ERR_ANO]
HAVING Count(*)>1 AND [DATESE] = [Centre].[DATESE]
AND [C_ERR_ANO] = [Centre].[C_ERR_ANO]
AND [LIBELLE] = [Centre].[LIBELLE])))
ORDER BY Centre.[REFERENCE], Centre.[DATESE], Centre.[C_ERR_ANO])
GROUP BY REFERENCE, DATESE, C_ERR_ANO
still , not working
i'm struggeling
Your group by clause needs to include all of the items in your select. Why not use:
select Centre.DATESE, Centre.C_ERR_ANO, Count (*)
Group by Centre.DATESE, Centre.C_ERR_ANO
HAVING COUNT (*) > 5
If you need other fields then you can add them, as long as you ensure the same fields appear in the select as the group by.
No idea what is going on with the formatting here!