Limit results of a joined table to the number of entries in the base table - sql

I use Lansweeper to keep track of all server assets.
At the moment I am working on a report, which shows which webservers are installed and running.
For this I have to join to tables, Table A contains the installed webserver software, table B contains the names of the services
The expected result should like this:
VM
Version
Class
Servicename
VM1
9
Tomcat
tomcat9
VM2
9
Tomcat
tomcat9
VM2
7
Tomcat
tomcat7
VM3
9
Tomcat
tomcat9
It is working fine, except for servers where multiple webservers are installed. If I have two webservers on a machine I get 4 results in the table. This is because I join based on the VM-ID, so the result looks like this:
VM
Version
Class
Servicename
VM1
9
Tomcat
tomcat9
VM2
9
Tomcat
tomcat9
VM2
7
Tomcat
tomcat7
VM2
9
Tomcat
tomcat7
VM2
7
Tomcat
tomcat9
VM3
9
Tomcat
tomcat9
This is the SQL statement for this result:
select a.VM, a.Version, a.Class, b.Servicename
from Installedsoftware as a
inner join Services as b on a.VM = b.VM
I totally understand that this happens because of two entries in table A und table B which results in 4 entries because of the join.
Is there a way to avoid this without adding a second join condition? Because this would only help in this scenario but not if I have two tomcat9 servers on the same machine.
Is there a way to limit the results in a way like "if Table A has only two entries for VM1, then show only two lines of the joined table"?

This seems like a groupwise-maximum problem, which has several potential approaches, but all encourage a predictable, deterministic row as opposed to "I don't care which row." One way is:
select a.VM, a.Version, a.Class, b.Servicename
from dbo.Installedsoftware as a
left outer join
(
SELECT VM, Servicename, rn = ROW_NUMBER() OVER
(PARTITION BY VM ORDER BY Servicename)
FROM dbo.Services
) as b on a.VM = b.VM
AND b.rn = 1;
You could get a little closer to "I don't care" by changing:
(PARTITION BY VM ORDER BY ##SPID)
Or to a pseudo-random row (at a performance cost) using:
(PARTITION BY VM ORDER BY NEWID())

Related

Query - Calculate the difference between 2 DB tables with the same columns

How do you calculate the difference between 2 DB tables with the same columns using query? They both have Columns as 'app', 'installs', 'usage'. Thanks in advance.
My notworking query
WITH apps AS (
SELECT app, installs_curr, usage_curr FROM (
SELECT app, installs AS installs_curr, usage AS usage_curr
FROM e5a.apps_2020_07
)
SELECT app, installs_prev, usage_prev FROM (
SELECT app, installs AS installs_prev, usage AS usage_prev
FROM e5a.apps_2020_06
)
)
SELECT app, installs_curr – installs_prev AS installs_delta, usage_curr – usage_prev AS usage_delta FROM apps
ORDER BY usage_delta DESC
**TABLE e5a.apps_2020_07**
app installs usage
snap 20 10
**TABLE e5a.apps_2020_06**
app installs usage
snap 12 8
**Result through calculation**
app installs usage
snap 8 2
It depends on how you want to treat values in one table but not the other. A good place to start is with join:
SELECT a7.app,
(a7.installs - a6.installs) AS installs_diff,
(a7.usage - a6.usage) AS usage_diff
FROM e5a.apps_2020_07 a7 JOIN
e5a.apps_2020_08 a6
ON a7.apps = a6.apps;
This include only apps that are in both tables.
You should fix your data model so you have only one table with the month as a column in the table.
Assuming that App is primary key, then you can simply subtract:
SELECT a.app, a.installs - b.installs installs_curr, a.usage - b.usage AS usage_curr
FROM e5a.apps_2020_07 a inner join e5a.apps_2020_06 b on (a.app = b.app)

Counting instances of value in postgres query

Bit of an SQL newbie question..
If I have a table along the lines of the following :
host fault fatal groupname
Host A Data smells iffy n research
Host B Flanklecrumpet needs a cuddle y production
Host A RAM loves EWE n research
Host Z One of the crossbeams gone askew on the treadle y research
.. and I want to get some stats, I can..
select count(distinct host) as hosts, count(host) as faults, group from tablename group by groupname
.. which gives me the number of faults and affected hosts per groupname.
hosts faults groupname
2 3 research
1 1 production
Can I, in the same query, show the number of fatal entries?
I would use aggregation, but in Postgres would phrase this as:
select groupname, count(distinct host) as hosts,
count(*) as num_faults,
count(*) filter (where fatal = 'Y') as num_fatal
from t
group by groupname;
use conditional aggregation
select count(distinct host) as hosts,
count(host) as faults,sum(case when fatal='y' then 1 else 0 end) as numberofenty,
groupname from tablename group by groupname

SQL Server take long to respond with nodejs

I used SQL Server as backend and node express as web server to make api's.
One api returns 10 results in 400ms, that is ok.
After some time, that api takes 7 to 10 seconds to respond with the same data.
Then I checked SQL Server and ran the same query on it, it takes 7 seconds for data display at first time.
Second time around, it takes 300 ms, after that the api returns the data within 400ms.
My question is: why does it takes 7 seconds to run the SQL query?
When I directly hit SQL Server, then the api responds within 400ms.
Why this?
This is my query:
SELECT Max(ord.code) code,
Max(os.orderstatus) orderstatus,
Max(cus.altercode) altercode,
Max(cus.NAME) NAME,
Max(cus.mobileno) mobileno,
Max(ord.createdonutc) createdonutc,
Count(otr.ordercode) noofitems,
Max(cus.appid) appid
FROM orders ord
LEFT OUTER JOIN orderstatus os
ON ord.code = os.ordercode
LEFT OUTER JOIN customers cus
ON cus.code = ord.customercode
LEFT OUTER JOIN order_tr otr
ON otr.ordercode = ord.code
WHERE os.orderstatus = 'PENDING'
GROUP BY otr.ordercode
ORDER BY code DESC

SQL Server Performance Query

I have some troubles with this query (view).
I'm using SQL Server 2012.
With few Record the query is fast but after that I add only 1000 records (Links) it becomes very slow (over 23 seconds)
I have to take a random Link for every host in database,so I used Row_Number and partition by.
Links table has 1000 records and host table has 10 record but the query is so slow
Any advice for increase performance?
UPDATE I need to get foreach Host a Random Link (could be 1 or 2 or 3 depends on Host.numLinksPerWork)
;WITH MyCte As
(
SELECT DISTINCT link.namUrl, host.uidHost, host.namHost AS Hostname,
[user].uidUser, usrProfile.UserName AS Username, host.numLinksPerWork,
referer.namUrl AS refererLink,host.Min, host.Max,ROW_NUMBER()
OVER (PARTITION BY host.numLinksPerWork, host.uidHost ORDER BY newid()) AS Number
FROM Links link JOIN
Users[user] ON [user].uidUser = link.codUser JOIN
Profile usrProfile ON usrProfile.UserId = [user].uidUser JOIN
Hosts host ON host.uidHost = link.codHost JOIN
Referers referer ON referer.codHost = host.uidHost JOIN
Referers referer2 ON referer.codUser = [user].uidUser
WHERE [user].flgBanned = 0
)
SELECT MyCte.uidHost, MyCte.uidUser, MyCte.namUrl, MyCte.refererLink,
MyCte.Hostname, MyCte.Username, MyCte.Min, MyCte.Max FROM MyCte
WHERE MyCte.Number <= MyCte.numLinksPerWork!
Similar Diagram
I Fixed the problem... The double join on the same table which is wrong OFC ,It slowed down the query!
Referers referer ON referer.codHost = host.uidHost JOIN
Referers referer2 ON referer.codUser = [user].uidUser
removing useless Join(s) it's fast!

Compare columns in a table and only show differences

I have two columns in the same table that I'm trying to compare. The issue is that they don't have to be identical to be considered "the same". Below I'll try to explain with an example.
Example:
HOST_NAME ENVIRONMENT SUBNET_ENVIRONMENT
host1 Production Prod
host2 Development(Dev)/Testing Non-Prod
host3 Development(Dev) Prod
host4 Production Non-Prod
host5 Testing/UAT Prod
host6 DR Prod
Essentially, if the "SUBNET_ENVIRONMENT" is Prod, the ENVIRONMENT should be "Production" as well. If the "SUBNET_ENVIRONMENT" is Non-Prod, the ENVIRONMENT should be anything besides "Production".
In this example, the first two would (host1 and host2) would be considered correct, and therefore be left out of the results. The following 4 (host{3-6}) are "different" so these are the ones that I want to be shown in the results of the query.
Below is a sample query for how I get the entire resultset. How can I modify this to only show the differences?
SELECT
HOST_NAME,
REPLACE(HOST_ENVIRONMENT,',','/') HOST_ENV,
HOST_SUBNET_ENV
FROM
HOST_TABLE
Should just be as simple as an OR:
SELECT
HOST_NAME,
REPLACE(HOST_ENVIRONMENT,',','/') HOST_ENV,
HOST_SUBNET_ENV
FROM
HOST_TABLE
WHERE (SUBNET_ENVIRONMENT = 'Prod' AND ENVIRONMENT <> 'Production')
OR (SUBNET_ENVIRONMENT = 'Non-Prod' AND ENVIRONMENT = 'Production')