I would like to consolidate a one to many relationship that outputs on different rows to a single row.
(select rate_value1
FROM xgenca_enquiry_event
INNER JOIN xgenca_enquiry_iso_code_translation
ON
xgenca_enquiry_event_rate.rate_code_id
= xgenca_enquiry_iso_code_translation.id
where xgenca_enquiry_event_rate.event_id = xgenca_enquiry_event.id
and ISO_code = 'PDIV') as PDIVrate,
(select rate_value1
FROM xgenca_enquiry_event
INNER JOIN xgenca_enquiry_iso_code_translation
ON
xgenca_enquiry_event_rate.rate_code_id
= xgenca_enquiry_iso_code_translation.id
where xgenca_enquiry_event_rate.event_id = xgenca_enquiry_event.id
and ISO_code = 'TAXR') as TAXrate
PDIVrate TAXrate
NULL 10.0000000
0.0059120 NULL
I would like the results on one row. Any help would be greatly appreciated.
Thanks.
You can use an aggregate function to perform this:
select
max(case when ISO_code = 'PDIV' then rate_value1 end) PDIVRate,
max(case when ISO_code = 'TAXR' then rate_value1 end) TAXRate
FROM xgenca_enquiry_event_rate r
INNER JOIN xgenca_enquiry_iso_code_translation t
ON r.rate_code_id = t.id
INNER JOIN xgenca_enquiry_event e
ON r.event_id = e.id
It looks like you are joining three tables are are identical in the queries. This consolidates this into a single query using joins.
Look here:
Can I Comma Delimit Multiple Rows Into One Column?
Simulate Oracle's LISTAGG() in SQL Server using STUFF:
SELECT Column1,
stuff((
SELECT ', ' + Column2
FROM tableName as t1
where t1.Column1 = t2.Column1
FOR XML PATH('')
), 1, 2, '')
FROM tableName as t2
GROUP BY Column1
/
Copied from here: https://github.com/jOOQ/jOOQ/issues/1277
Related
I have a query that does a select with joins from multiple tables that contains in total about 90 million rows. I only need data from the last 30 days. The problem is that when I run the select query the sql server throws a timeout while the query is running and new records are not created during this time frame. This query takes about 5 seconds to complete.
I would like to optimise this query so that it wont go through the entire tables looking at the datetime and would only search from the latest entries.
Right now it seems that I would need to index datetime column. Please advise if I need to create indexes or if there is another way to optimise this query.
SELECT [table1].Column1 AS InvoiceNo,
'ND' AS VATRegistrationNumber,
'ND' AS RegistrationNumber,
Column2 AS Country,
[table2].Column3 + ' ' + [table2].Column4 AS Name,
CAST([table1].Column5 AS date) AS InvoiceDate,
'SF' AS InvoiceType,
'' AS SpecialTaxation,
'' AS VATPointDate,
ROUND([table1Line].Column6, 2) AS TaxableValue,
CASE
WHEN [table1Line].Column7 = 9 THEN 'PVM2'
WHEN [table1Line].Column7 = 21 THEN 'PVM1'
WHEN [table1Line].Column7 = 0 THEN 'PVM14'
END AS TaxCode,
CAST([table1Line].Column7 AS int) AS TaxPercentage,
table1Line.Column8 - ROUND([table1Line].Column6, 2) AS Amount,
'' AS VATPointDate2,
[table1].Column1 AS InvoiceNo,
'' AS ReferenceNo,
'' AS ReferenceDate,
[table1].CustomerPersonID AS CustomerID
FROM [table1]
INNER JOIN [table2] ON [table1].CustomerPersonID = [table2].ID
INNER JOIN [table3] ON [table2].Column9 = [table3].ID
INNER JOIN [table1Line] ON [table1].ID = [table1Line].table1ID
INNER JOIN [table4] ON table1Line.TaxID = Tax.ID
INNER JOIN [table5] ON [table1].CompanyID = Company.ID
INNER JOIN table6 ON [table1].SalesChannelID = table6.ID
WHERE Column5 LIKE '%date%'
AND table6.id = 5
OR table6.id = 2
AND Column5 LIKE '%date%'
ORDER BY Column5 DESC;
First things first, each database runs a little differently because the optimizer has been running and figuring out how the unique circumstances can be improved and continuously tries to make common things run better.
There's also versioning differences that also play a part is the performance of the server.
Besides that stuff, Here's a few things to do to optimize this query.
When working with Joins, Your Joined table comes first then compare against the already specified table.
For example t2 checks against t1:
select t1.name, t2.car
from customers as t1
left join purchases as t2
on t2.customerid = t1.customerid
The next thing I see is the Like condition in the Where part of the code.
The stored date that it's finding is stored as text in your example.
I would recommend processing the date as a datetime instead of a string type of datatype.
I would include that in the code below, but I'm not sure what the format looks like for your string of text.
%date% is the same thing as saying "Contains date".
This takes the date string, and tries to see if it matches in every position of characters from left to right.
So if your date text is 20200130, it will check to see if it matches 2date0200130, then tries 20date200130, then tries 202date00130, etc.
It will significantly increase the time it takes to process.
I also see that the date is being searched accidently two times instead of one.
I would recommend doing:
WHERE LTRIM(RTRIM(Column5)) LIKE 'date'
As for the Inner Joins, I would not use them.
Use the Left join, and then in the Where, I would make sure it had no Null values for that joined data.
This makes the Left Join work the same as the Inner Join and runs more optimally when you are running the query.
For Instance, the first Join would look like this:
FROM [table1]
LEFT JOIN [table2] ON [table2].ID = [table1].CustomerPersonID
WHERE table2.id IS NOT NULL
I see an error in the code in the Where statement:
AND table6.id = 5
OR tables6.id = 2
This should be:
AND (tables6.id = 5 OR tables6.id = 2)
So here should be an optimized version of your code:
SELECT [table1].Column1 AS InvoiceNo,
'ND' AS VATRegistrationNumber,
'ND' AS RegistrationNumber,
Column2 AS Country,
[table2].Column3 + ' ' + [table2].Column4 AS Name,
CAST([table1].Column5 AS date) AS InvoiceDate,
'SF' AS InvoiceType,
'' AS SpecialTaxation,
'' AS VATPointDate,
ROUND([table1Line].Column6, 2) AS TaxableValue,
(CASE WHEN [table1Line].Column7 = 9 THEN 'PVM2'
WHEN [table1Line].Column7 = 21 THEN 'PVM1'
WHEN [table1Line].Column7 = 0 THEN 'PVM14'
ELSE '' END ) AS TaxCode,
CAST([table1Line].Column7 AS int) AS TaxPercentage,
table1Line.Column8 - ROUND([table1Line].Column6, 2) AS Amount,
'' AS VATPointDate2,
[table1].Column1 AS InvoiceNo,
'' AS ReferenceNo,
'' AS ReferenceDate,
[table1].CustomerPersonID AS CustomerID
FROM [table1]
LEFT JOIN [table2] ON [table2].ID = [table1].CustomerPersonID
LEFT JOIN [table3] ON [table3].ID = [table2].Column9
LEFT JOIN [table1Line] ON [table1Line].table1ID = [table1].ID
LEFT JOIN [table4] ON [table4].ID = table1Line.TaxID
LEFT JOIN [table5] ON [table5].ID = [table1].CompanyID
LEFT JOIN [table6] ON table6.ID = [table1].SalesChannelID
WHERE table2.ID IS NOT null
AND table3.ID IS NOT null
AND table1Line.ID IS NOT null
AND table4.ID IS NOT null
AND table5.ID IS NOT null
AND table6.ID IS NOT null
AND LTRIM(RTRIM(Column5)) LIKE 'date'
AND (table6.id = 5 OR table6.id = 2)
ORDER BY Column5 DESC;
This is a sub query:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass FROM IMP_ELEMENT as t1 WHERE TRIM(t1.project) = '99999';
This is the result:
This is my second sub query:
SELECT t2.element_id, t2.building, t2.floor_id, t2.deleted, t2.ELEMENT_MARK
FROM IMP_MODEL_GEOMETRY as t2
WHERE TRIM(t2.project) = '99999' AND TRIM(t2.building) = '1' AND TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND t2.deleted = 0
ORDER BY t2.ELEMENT_MARK;
This is the result:
Now i'd like to combine them:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass, t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM IMP_ELEMENT as t1
LEFT JOIN IMP_MODEL_GEOMETRY as t2 ON t1.element_mark = t2.element_mark
WHERE TRIM(t2.project) = '99999' AND TRIM(t2.building) = '1' AND TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND t2.deleted = 0
ORDER BY t2.element_id;
And this is the result:
So what do i want?
I want only one result per "element_id".
I first want to SELECT"element_id" and then i want to find a match in the second table. To find a match i will use "element_mark". What is wrong in my query? why do i get multiple element_id?
As suggested by one of the comments, you probably have missed the WHERE clause in the first table. Try this query instead:
SELECT
t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass, t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM
IMP_ELEMENT as t1
LEFT JOIN
IMP_MODEL_GEOMETRY as t2
ON
t1.element_mark = t2.element_mark
WHERE
TRIM(t2.project) = '99999' AND
TRIM(t2.building) = '1' AND
TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND
t2.deleted = 0 AND
TRIM(t1.project) = '99999'
ORDER BY t2.element_id;
When joining two tables, in your case with a left join, if there are multiple matches on the join condition, multiple rows will be in the result set. You are joining based on element_mark- so for the first record of the first query- 3 rows will be returned in your result. What I would suggest is put the second table at the left part of the query or do a RIGHT JOIN. This way, because element_mark looks unique in the first table, you will get one record per element_id.
If you want to keep all elements and get matching information -- if any -- from the second table, then you want the LEFT JOIN. However, all conditions on the second table need to be in the ON clause:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass,
t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM IMP_ELEMENT t1 LEFT JOIN
IMP_MODEL_GEOMETRY t2
ON t1.element_mark = t2.element_mark AND
TRIM(t2.project) = '99999' AND
TRIM(t2.building) = '1' AND
TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND
t2.deleted = 0
ORDER BY t2.element_id;
There is no WHERE clause because all the filters are on the second table.
I made this view in sql server to combine the values of 2 records of multiple columns. But the problem with this solution is that you need a concat for every column in table2. I would like to know if it is possible to do the concat part with a loop and a dynamic variable for the column numbers (columns in table2 are called 1,2,3,4,5....) of table2.
SELECT
dbo.table1.lot_id AS lot,
dbo.table1.hybird_id AS hybrid,
concat(
LEFT( (SELECT dbo.table2.[1] FROM dbo.table2 WHERE dbo.table2.parentals_id = dbo.table1.parental_male_id AND dbo.table2.lot_id = dbo.table1.lot_id) , 1),
LEFT( (SELECT dbo.table2.[1] FROM dbo.table2 WHERE dbo.table2.parentals_id = dbo.table1.parental_female_id AND dbo.table2.lot_id = dbo.table1.lot_id) , 1)
) AS '1',
--above concat x31 times more
FROM dbo.table2
INNER JOIN dbo.table1 ON dbo.table2.lot_id = dbo.table1.lot_id
GROUP BY dbo.table1.lot_id, dbo.table1.hybird_id,
dbo.table1.parental_male_id,
dbo.table1.parental_female_id
I tried a few things but nothing worked, any ideas?
Try to simplify it a bit, kind of
SELECT lot, hybrid, parental_male_id, parental_female_id
concat(Left(m.[1],1), left(f.[1], 1)) AS [1]
--,..
FROM (
SELECT dbo.table1.lot_id AS lot
, dbo.table1.hybird_id AS hybrid
, dbo.table1.parental_male_id
, dbo.table1.parental_female_id
FROM dbo.table2
INNER JOIN dbo.table1 ON dbo.table2.lot_id = dbo.table1.lot_id
GROUP BY dbo.table1.lot_id, dbo.table1.hybird_id,
dbo.table1.parental_male_id,
dbo.table1.parental_female_id
) t
JOIN dbo.table2 m ON m.parentals_id = t.parental_male_id AND m.lot_id = lot)
JOIN dbo.table2 f ON f.parentals_id = t.parental_female_id AND f.lot_id = lot)
Suppose I have serial number, test name and few other columns, i want to write a condition if TESTNAME is null for a particular serial number then set the TESTNAME to blank else perform inner join
SELECT
(A.PTNUMBER + '-' +A.SL_NO) AS ENUMBER,
D.ENGINEER AS REQ, D.DATETIME as "DATE",
(select Value
from DROPDOWN
where B.TEST_NAME=CONVERT(VARCHAR,DropdownID)) TESTNAME,
TABLE_NAME AS TABLETD
FROM INSPECTION D
INNER JOIN TABLEA A ON D.ENGID = CONVERT(VARCHAR,A.EN_ID)
INNER JOIN TABLEB B ON B.ENGID = CONVERT(VARCHAR,A.EN_ID)
INNER JOIN TABLEC C ON C.ENGID = CONVERT(VARCHAR,A.EN_ID)
not sure what you mean by set testname to blank but if you meant to be using a SELECT query then you can do like
select *,
case when TESTNAME is null and serial_number = some_value then '' end as TESTNAME
from mytable
You could combine a case expression and coalesce() along with your join to choose the value you want to return.
select serial_number, ...
,case when coalesce(testname,'') <> ''
then t2.testname
else coalesce(testname,'') end
from t
inner join t2
on ...
You can use isnull() or coalesce() in sql server to return a different value to replace null.
select isnull(testname,'')
or
select coalesce(testname,'')
The main difference between the two is that coalesce() can support more than 2 parameters, and it selects the first one that is not null. More differences between the two are answered here.
select coalesce(testname,testname2,'')
coalesce() is also standard ANSI sql, so you will find it in most RDBMS. isnull() is specific to sql server.
Reference:
isnull() - msdn
coalesce() - msdn
SELECT (A.PTNUMBER + '-' + A.SL_NO) AS ENUMBER,
D.ENGINEER AS REQ,
D.DATETIME as "DATE",
case
when SerialNo = xxx and TESTNAME is null then ''
else (select Value from DROPDOWN where B.TEST_NAME = CONVERT(VARCHAR, DropdownID))
end AS TESTNAME,
TABLE_NAME AS TABLETD
FROM INSPECTION D
INNER JOIN TABLEA A ON D.ENGID = CONVERT(VARCHAR, A.EN_ID)
INNER JOIN TABLEB B ON B.ENGID = CONVERT(VARCHAR, A.EN_ID)
INNER JOIN TABLEC C ON C.ENGID = CONVERT(VARCHAR, A.EN_ID);
I have the following query that I'm trying to join two tables matching their ID so I can get the duplicated values in "c.code". I've tried a lot of queries but nothing works. I have a 500k rows in my database and with this query I only get 5k back, which is not right. Im positive it's at least 200K. I also tried to use Excel but it's too much for it to handle.
Any ideas?
Thanks in advance, everyone.
SELECT c.code, c.name as SCT_Name, t.name as SYNONYM_Name, count(c.code)
FROM database.Terms as t
join database.dbo.Concepts as c on c.ConceptId = t.ConceptId
where t.TermTypeCode = 'SYNONYM' and t.ConceptTypeCode = 'NAME_Code' and c.retired = '0'
Group by c.code, c.name, t.name
HAVING COUNT(c.code) > = 1
Order by c.code
with data as (
select c.code, c.name as SCT_Name, t.name as SYNONYM_Name
from database.Terms as t inner join database.dbo.Concepts as c
on c.ConceptId = t.ConceptId
where
t.TermTypeCode = 'SYNONYM'
and t.ConceptTypeCode = 'NAME_Code'
and c.retired = '0'
)
select *
--, (select count(*) from data as d2 where d2.code = data.code) as code_count
--, count(*) over (partition by code) as code_count
from data
where code in (select code from data group by code having count(*) > 1)
order by code
If you want just duplicates of c.code, your Group By is wrong (and so is your Having clause). Try this:
SELECT c.code
FROM database.Terms as t
join database.dbo.Concepts as c on c.ConceptId = t.ConceptId
where t.TermTypeCode = 'SYNONYM' and t.ConceptTypeCode = 'NAME_Code' and c.retired = '0'
Group by c.code
HAVING COUNT(c.code) > 1
This will return all rows where you have more than one c.code value.
You need to use INTERSECT instead of JOIN. Basically you perform the select on the first table then intersect with the second table. The result is the duplicate rows.
Only select the id column, though, otherwise the intersect won't work as expected.