Join different tables depending on field values - sql

I have the following sql view result which contains the audited changes for every field for every table in the system:
In this case the above image tell us that both read and write permissions were revoked for the user Lucas for the subscription called MySubscription.
I need to display that info in a grid however that is not what I want to display, I mean, I donĀ“t want to display IDs. I need to display "Read" instead of 50, "Write" instead of 51, "Lucas" instead of 1 and "MySubscription" instead of 6.
To do that I would like to improve the sql view to get the values instead of their IDs as I mention above. The result that I am looking for is this one:
The database contains the tables Subscriptions, ProductPermissions and TenantUsers to get the needed info using joins.
Could you please give me some clues about how could I achieve what I need? Thank you.

You could do this with a series of LEFT JOINs, some casting might be required to get the datatype of the joining column the same as NewValue (I've assumed a column called Name in all your joining tables, this may need changing):
SELECT a.AuditLogId,
a.Operation,
a.[Table],
a.RowId,
a.Name,
[OldValue] = COALESCE(s_Old.Name, pp_old.Name, t_Old.Name),
[NewValue] = COALESCE(s_New.Name, pp_New.Name, t_New.Name)
FROM AuditLog a
LEFT JOIN Subscriptions s_Old
ON a.OldValue = CAST(s_Old.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_Old
ON a.OldValue = CAST(p_Old.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_Old
ON a.OldValue = CAST(t_Old.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
LEFT JOIN Subscriptions s_New
ON a.NewValue = CAST(s_New.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_New
ON a.NewValue = CAST(p_New.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_New
ON a.NewValue = CAST(t_New.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
If required you could then PIVOT this into one row per transaction:
SELECT a.AuditLogId,
a.Operation,
a.[Table],
a.RowId,
[OldSubscriptionValue] = MAX(s_old.Name),
[OldProductPermissionValue] = MAX(pp_old.Name),
[OldTennantUserValue] = MAX(t_old.Name),
[NewSubscriptionValue] = MAX(s_New.Name),
[NewProductPermissionValue] = MAX(pp_New.Name),
[NewTennantUserValue] = MAX(t_New.Name)
FROM AuditLog a
LEFT JOIN Subscriptions s_Old
ON a.OldValue = CAST(s_Old.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_Old
ON a.OldValue = CAST(p_Old.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_Old
ON a.OldValue = CAST(t_Old.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
LEFT JOIN Subscriptions s_New
ON a.NewValue = CAST(s_New.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_New
ON a.NewValue = CAST(p_New.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_New
ON a.NewValue = CAST(t_New.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
GROUP BY a.AuditLogId, a.Operation, a.[Table], a.RowId;
It is a pretty dirty solution, I would be inclined to store this data in the format you want to select it in i.e. instead of 50/51, store read/write directly in the NewValue column.
Alternatively, if you did want the second format with one row per transaction then I'd be inclined to store it in this way. It could be worth reading about the Entity-Attribute-Value Antipattern.

You could PIVOT the data and LEFT JOIN to the lookup tables. Then UNPIVOT if necessary.

If you simply need to display words instead of numbers, create a lookup table that maps between the number and the word you want to display:
create table NewValueText (
NewValue integer,
Description char(20)
);
insert into NewValueText values
(50, 'Read'),
(51, 'Write'); --etc.
--MyTable is your table that contains the NewValue column.
select Description from MyTable
inner join NewValueText on MyTable.NewValue = NewValueText.NewValue;

You could try joining in your tables where your values are specific. You'll need to create a look-up table for other values other than Really it's a dirty solution because it means hard coding your NewValue fields into the SQL:
...
FROM
audit LEFT JOIN
mysubscription ON audit.rowid = mysubscription.tenantuserid
AND audit.newvalue = 1
LEFT JOIN
lookup_list ON audit.rowid = lookup_list.lookup_id
AND audit.newvalue <> 1
...
That may work for you.

Related

string_agg is to slow with big data and i need a faster solution

I am working with contacting a string from a result and it is taking to long to execute
this is the solution I have:
declare #damagedParties table (caseid varchar(max),FirstName varchar(max),LastName varchar(max),damagedName varchar(max))
insert #damagedParties
select t.caseid,ped.FirstName as FirstName,ped.LastName,concat(ped.FirstName,' ',ped.LastName) as damagedName
from [Case] t
inner join [KCC].[dbo].[Party] p1 on p1.CaseId = t.caseid
LEFT JOIN Person ped ON ped.PersonOrBusinessId = ped.PersonOrBusinessId and p1.PartyTypeRefData = 'kpcparty$PARTY_INJUREDPARTY_F'
select string_agg(d.damagedName,', ')
from #damagedParties d
group by d.caseid
The LEFT JOIN condition in the first query joins the Person table to itself on PersonOrBusinessId. Presumably, the JOIN should be from Person table to the Party table? Something like this
insert #damagedParties
select t.caseid, ped.FirstName, ped.LastName,
concat(ped.FirstName,' ',ped.LastName) as damagedName
from [Case] t
join [KCC].[dbo].[Party] p1 on p1.CaseId = t.caseid
left join Person ped ON p1.PersonOrBusinessId = ped.PersonOrBusinessId
where p1.PartyTypeRefData = 'kpcparty$PARTY_INJUREDPARTY_F';

Passing different column values to where clause

SELECT pims.icicimedicalexaminerreport.id,
pims.icicimerfemaleapplicant.adversemenstrualid,
pims.icicimerfemaleapplicant.pregnantid,
pims.icicimerfemaleapplicant.miscarriageabortionid,
pims.icicimerfemaleapplicant.breastdiseaseid,
pims.pimscase.tiannumber
FROM pims.pimscase
INNER JOIN pims.digitization
ON pims.pimscase.digitizationid = pims.digitization.id
INNER JOIN pims.medicalexaminerreport
ON pims.digitization.medicalexaminerreportid =
pims.medicalexaminerreport.id
INNER JOIN pims.icicimedicalexaminerreport
ON pims.medicalexaminerreport.id =
pims.icicimedicalexaminerreport.id
INNER JOIN pims.icicimerfemaleapplicant
ON pims.icicimedicalexaminerreport.id =
pims.icicimerfemaleapplicant.id
WHERE pims.pimscase.tiannumber = 'ICICI1234567890'
which gives me the following output
Now I want to use the above output values to select the rows from the table "YesNoAnswerWithObservation"
I imagine it should look something like this Select * from YesNoAnswerWithObservation Where Id in (22,27,26,...23)
Only instead of typing the values inside IN clause I want to use the values in each column resulting from above-mentioned query.
I tried the below code but it returns all the rows in the table rather than rows mentioned inside the In
SELECT pims.yesnoanswerwithobservation.observation,
graphitegtccore.yesnoquestion.description,
pims.yesnoanswerwithobservation.id ObservationId
FROM pims.yesnoanswerwithobservation
INNER JOIN graphitegtccore.yesnoquestion
ON pims.yesnoanswerwithobservation.yesnoanswerid =
graphitegtccore.yesnoquestion.id
WHERE EXISTS (SELECT pims.icicimedicalexaminerreport.id,
pims.icicimerfemaleapplicant.adversemenstrualid,
pims.icicimerfemaleapplicant.pregnantid,
pims.icicimerfemaleapplicant.pelvicorgandiseaseid,
pims.icicimerfemaleapplicant.miscarriageabortionid,
pims.icicimerfemaleapplicant.gynocologicalscanid,
pims.icicimerfemaleapplicant.breastdiseaseid,
pims.pimscase.tiannumber
FROM pims.pimscase
INNER JOIN pims.digitization
ON pims.pimscase.digitizationid =
pims.digitization.id
INNER JOIN pims.medicalexaminerreport
ON pims.digitization.medicalexaminerreportid =
pims.medicalexaminerreport.id
INNER JOIN pims.icicimedicalexaminerreport
ON pims.medicalexaminerreport.id =
pims.icicimedicalexaminerreport.id
INNER JOIN pims.icicimerfemaleapplicant
ON pims.icicimedicalexaminerreport.id =
pims.icicimerfemaleapplicant.id
WHERE pims.pimscase.tiannumber = 'ICICI1234567890')
Any help or a nudge in the right direction would be greatly appreciated
Presumably you want the ids from the first query:
SELECT awo.observation, ynq.description, ynq.id as ObservationId
FROM pims.yesnoanswerwithobservation awo JOIN
graphitegtccore.yesnoquestion ynq
ON awo.yesnoanswerid = ynq.id
WHERE ynq.id = (SELECT mer.id
FROM pims.pimscase c JOIN
pims.digitization d
ON c.digitizationid = d.id JOIN
pims.medicalexaminerreport mer
ON d.medicalexaminerreportid = mer.id JOIN
pims.icicimedicalexaminerreport imer
ON mer.id = imer.id JOIN
pims.icicimerfemaleapplicant ifa
ON imer.id = ifa.id
WHERE c.tiannumber = 'ICICI1234567890'
) ;
Notice that table aliases make the query much easier to write and to read.

Subquery in FROM cannot refer to other relations of same query level

I have 4 tables from which I want to select data based on some conditions: organisationunit,orgunitgroupmembers,orgunitgroup, orgunitgroupsetmember
and the select code:
SELECT *
FROM organisationunit,
orgunitgroupmembers,
orgunitgroup,
orgunitgroupsetmembers
WHERE organisationunit.comment = '1'
AND orgunitgroupmembers.organisationunitid = organisationunit.organisationunitid
AND orgunitgroup.orgunitgroupid = orgunitgroupmembers.orgunitgroupid
AND orgunitgroupsetmembers.orgunitgroupid = orgunitgroup.orgunitgroupid
AND orgunitgroupsetmembers.orgunitgroupsetid = '15633'
It does return what I want but now, I want to add these part
(select name
from organisationunit tt
where tt.organisationunitid =organisationunit.parentid) as rayon
after the select method:
SELECT *
FROM organisationunit,
orgunitgroupmembers,
orgunitgroup,
orgunitgroupsetmembers,
(SELECT NAME
FROM organisationunit tt
WHERE tt.organisationunitid = organisationunit.parentid) AS rayon
WHERE organisationunit.comment = '1'
AND orgunitgroupmembers.organisationunitid = organisationunit.organisationunitid
AND orgunitgroup.orgunitgroupid = orgunitgroupmembers.orgunitgroupid
AND orgunitgroupsetmembers.orgunitgroupid = orgunitgroup.orgunitgroupid
AND orgunitgroupsetmembers.orgunitgroupsetid = '15633'
and it gives the error
Subquery in FROM cannot refer to other relations of same query level
As you can see the table organisationunit has a parentid, which is a number and the same table organisationunit contains the name for that parentid. So I want at the end of the row in one column show the name of that parentid.
P.S I hope you got want I wanted, otherwise please feel free to ask the questions. Its first time that I do DB manipulations so far, if something is too obvious, believe me its NOT for me.
If am not wrong this is what you need. Here I made few changes.
Converted old style of join to proper INNER JOIN and moved the filters to where clause .
Next as mentioned in error you cannot refer the other tables in from clause of subquery. Actually you need to use correlated subquery to find the parent name or self join. or even a cross apply if it is supported
SELECT *,
(SELECT NAME
FROM organisationunit tt
WHERE tt.organisationunitid = organisationunit.parentid) AS rayon
FROM organisationunit
INNER JOIN orgunitgroupmembers
ON orgunitgroupmembers.organisationunitid = organisationunit.organisationunitid
INNER JOIN orgunitgroup
ON orgunitgroup.orgunitgroupid = orgunitgroupmembers.orgunitgroupid
INNER JOIN orgunitgroupsetmembers
ON orgunitgroupsetmembers.orgunitgroupid = orgunitgroup.orgunitgroupid
WHERE organisationunit.comment = '1'
AND orgunitgroupsetmembers.orgunitgroupsetid = '15633'
or even a self join to the same table to find the parent details.
SELECT *,
tt.NAME AS rayon
FROM organisationunit
INNER JOIN orgunitgroupmembers
ON orgunitgroupmembers.organisationunitid = organisationunit.organisationunitid
INNER JOIN orgunitgroup
ON orgunitgroup.orgunitgroupid = orgunitgroupmembers.orgunitgroupid
INNER JOIN orgunitgroupsetmembers
ON orgunitgroupsetmembers.orgunitgroupid = orgunitgroup.orgunitgroupid
INNER JOIN organisationunit tt
ON tt.organisationunitid = organisationunit.parentid
WHERE organisationunit.comment = '1'
AND orgunitgroupsetmembers.orgunitgroupsetid = '15633'
To get the name of the parent, use a self-join. Include one more reference to organisationunit in the from clause, with an alias tt or whatever. Something like this :
select A.*, B.*, C.*, D.*. tt.name as Rayon from organisationunit A,orgunitgroupmembers B,orgunitgroup C, orgunitgroupsetmembers D, organisationunit tt
where organisationunit.comment='1'
and orgunitgroupmembers.organisationunitid=organisationunit.organisationunitid
and orgunitgroup.orgunitgroupid =orgunitgroupmembers.orgunitgroupid
and orgunitgroupsetmembers.orgunitgroupid=orgunitgroup.orgunitgroupid
and orgunitgroupsetmembers.orgunitgroupsetid='15633'
and tt.organisationunitid =A.organisationunit.parentid
Of course, you may want to note that if the datasets are large, self-join may have some performance issues, in that case, you can use multi-step operation after selecting into temporary tables or whatever.

Inner join tables

I have SQL table Policy that contains column as PolicyNumber which has value 'CCL-9997-10497'
and another table PolicyImages which also has column PolicyNumber which has value 'CCL-9997-000010497'
I wanted to inner join both these table on PolicyNumber ?
How can I achieve it ?
Your two tables have different format of PolicyNumber so you need some kind of computation.
I think below query will help you
SELECT a.* FROM
FROM Table1 a INNER JOIN Table1 b ON a.PolicyNumber =
Replace(b.PolicyNumber,'-' + right(b.PolicyNumber,charindex('-',REverse(b.PolicyNumber))-1),
'-' + convert(varchar,Convert(Decimal,right(b.PolicyNumber,charindex('-',REverse(b.PolicyNumber))-1)))
)
This should do it:
SELECT *
FROM Policy
INNER JOIN PolicyImageq ON Policy.PolicyNumber = PolicyImages.PolicyNumber
If this is a one-time mistake, then you can do:
Policy p join
PolicyImages pi
on p.PolicyNumber = pi.PolicyNumber or
(p.PolicyNumber = 'CCL-9997-10497' and pi.PolicyNumber = 'CCL-9997-000010497')
If this is a formatting issue, then the solution is actually database-specific.

SQL Creating a temp table for this Query

I want to create a temp table to store this query so that I can then update another table.
SELECT SaginawUtilityData.ServiceFrom, SaginawUtilityData.ServiceThru,
BillingMonth = dbo.fn_MonthWithMostDaysInRange(ServiceFrom, ServiceThru),
SaginawUtilityData.Usage, SaginawUtilityData.UtilityCharges
FROM SaginawUtilityData
JOIN tblMEP_CustomerAccounts
ON SaginawUtilityData.AccountNumber = tblMEP_CustomerAccounts.AccountNumber
JOIN tblMEP_Customers
ON tblMEP_CustomerAccounts.CustomerID = tblMEP_Customers.ID
JOIN tblMEP_UtilityCompanies
ON tblMEP_UtilityCompanies.ID = tblMEP_CustomerAccounts.UtilityCompanyID
JOIN tblMEP_Meters
ON tblMEP_CustomerAccounts.ID = tblMEP_Meters.CustomerAccountID
WHERE tblMEP_Customers.ID = 43
It would be great if you can just do the update: this is the other table and the columns I want to insert from the table above into this one:
SELECT tblMEP_MonthlyDATA.CycleStartDate, tblMEP_MonthlyDATA.CycleEndDate,
tblMEP_MonthlyDATA.BillingMonth, tblMEP_MonthlyDATA.Consumption,
tblMEP_MonthlyDATA.Charge
FROM tblMEP_MonthlyData
Thanks.
I'm uncertain whether I really understand what you're asking but I think you're asking how you can put the data from the top query straight into the table columns shown in the bottom query, so:
INSERT tblMEP_MonthlyDATA (
CycleStartDate, CycleEndDate, BillingMonth, Consumption, Charge)
SELECT
SaginawUtilityData.ServiceFrom,
SaginawUtilityData.ServiceThru,
dbo.fn_MonthWithMostDaysInRange(ServiceFrom, ServiceThru),
SaginawUtilityData.Usage,
SaginawUtilityData.UtilityCharges
FROM SaginawUtilityData
JOIN tblMEP_CustomerAccounts ON SaginawUtilityData.AccountNumber =
tblMEP_CustomerAccounts.AccountNumber
JOIN tblMEP_Customers ON tblMEP_CustomerAccounts.CustomerID = tblMEP_Customers.ID
JOIN tblMEP_UtilityCompanies ON tblMEP_UtilityCompanies.ID =
tblMEP_CustomerAccounts.UtilityCompanyID
JOIN tblMEP_Meters ON tblMEP_CustomerAccounts.ID = tblMEP_Meters.CustomerAccountID
WHERE
tblMEP_Customers.ID = 43 --or other set of conditions
Hope this helps (or is at least vaguely relevant to what you want to know)