Strange result from a script - sql-server-2014

Hope you can enlighten me.
I'm running this script:
SELECT DISTINCT
DB_Name(Database_id) AS 'DatabaseName',
V.OBJECT_ID AS ObjectId,
Object_Name(V.Object_id) AS ObjectName,
V.Index_ID AS IndexId,
U.name as IndexName,
V.Index_Type_Desc AS IndexDescription,
V.avg_record_size_in_bytes,
V.record_count,
STATS_DATE(V.object_id, V.index_id) AS 'lastupdated',
CONVERT([varchar](512), round(Avg_Fragmentation_In_Percent, 3)) AS 'AvgFragmentationInPercent'
FROM
sys.dm_db_index_physical_stats(db_id(), NULL, NULL, NULL, 'detailed') V
JOIN
sys.indexes U ON V.object_id = U.object_id AND V.index_id = U.index_id
WHERE
V.OBJECT_ID IS NOT NULL
AND U.name = 'Add_Remove_Programs_64_DATA_AK'
ORDER BY
IndexName
I get a result I didn't expect:
DatabaseName ObjectId ObjectName IndexId IndexName IndexDescription avg_record_size_in_bytes record_count lastupdated AvgFragmentationInPercent
CM_PBN 101575400 Add_Remove_Programs_64_DATA 3 Add_Remove_Programs_64_DATA_AK NONCLUSTERED INDEX 96,899 1966 2018-06-07 16:54:04.610 100
CM_PBN 101575400 Add_Remove_Programs_64_DATA 3 Add_Remove_Programs_64_DATA_AK NONCLUSTERED INDEX 98,536 41 2018-06-07 16:54:04.610 0
CM_PBN 101575400 Add_Remove_Programs_64_DATA 3 Add_Remove_Programs_64_DATA_AK NONCLUSTERED INDEX 104,797 112316 2018-06-07 16:54:04.610 3.561
As you can see the result contains a single index but shows up three times. I have no idea why. So I hope I am just blind not seeing the obvious reason. Thank you very much for your efforts.

Related

How can you reference a column based on the average on another column in MySQL?

We have a scenario where users answer some questions related to a parent entity that we'll call a widget. Each question has both a numeric and word answer. Multiple users answer each question for a given widget.
We then display a row for each widget with the average numeric answer for each question. We do that using a MySQL pseudo-pivot with dynamic columns as detailed here So we end up with something like:
SELECT widget_id, ...
ROUND(IFNULL(AVG(CASE
WHEN LOWER(REPLACE(RQ.question, ' ', '_')) = 'overall_size' THEN
if(RA.num = '', 0, RA.num) END),0) + .0001, 2) AS `raw_avg_overall_size`,
...
... where overall_size would be one of the question types related to the widget and might have "answers" from 5 users like 1,2,2,3,1 to that question for a given widget_id based on the answer options below:
Answers
answer_id
answer_type
num
word
111
overall_size
1
x-large
112
overall_size
2
large
113
overall_size
3
medium
114
overall_size
4
small
115
overall_size
5
x-small
So we would end up with a row that had something like this:
widget_id
average_overall_size
115
1.80
What we can't figure out is then given if we round 1.80 to zero precision we get 2 in this example which is the word value 'large' from our data above. We like to include that in the query output too so that end up with:
widget_id
raw_average_overall_size
average_overall_size
115
1.80
large
The issue is that we do not know the average for the row until the query runs. So how can we then reference the word value for that average answer in the same row when executing the query?
As mentioned we are pivoting into a variable and then run another query for the full execution. So if we join in the pivot section, that subquery looks something like this:
SET #phase_id = 1;
SET SESSION group_concat_max_len = 100000;
SET #SQL = NULL;
SET #NSQL = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT(
'ROUND(IFNULL(AVG(CASE
WHEN LOWER(REPLACE(RQ.short_question, '' '', ''_'')) = ''',
nsq,
''' THEN
if(RA.answer = '''', 0, RA.answer) END),0) + .0001, 2) AS `',
CONCAT('avg_raw_',nsq), '`,
REF.value, -- <- ******* THIS FAILS **** --
ROUND(IFNULL(STDDEV(CASE
WHEN LOWER(REPLACE(RQ.short_question, '' '', ''_'')) = ''',
nsq,
''' THEN RA.answer END), 0) + .0001, 3) AS `',
CONCAT('std_dev_', nsq), '`
'
)
ORDER BY display_order
) INTO #NSQL
FROM (
SELECT FD.ref_value, FD.element_name, RQ.display_order, LOWER(REPLACE(RQ.short_question, ' ', '_')) as nsq
FROM review_questions RQ
LEFT JOIN form_data FD ON FD.id = RQ.form_data_id
LEFT JOIN ref_values RV on FD.ref_value = RV.type
WHERE RQ.phase_id = #phase_id
AND FD.element_type = 'select'
AND RQ.is_active > 0
GROUP BY FD.element_name
HAVING MAX(RV.key_name) REGEXP '^[0-9]+$'
) nq
/****** suggested in 1st answer ******/
LEFT JOIN ref_values REF ON REF.`type` = nq.ref_value
AND REF.key_name = ROUND(CONCAT('avg_raw_',nsq), 0);
So we need the word answer (from the REF join's REF.value field in the above code) in the pivot output, but it fails with 'Unknown column REF.value. If we put REF.value in it's parent query field list, that also fails with the same error.
You'll need to join the table/view/query again to get the 'large' value.
For example:
select a.*, b.word
from (
-- your query here
) a
join my_table b on b.answer_id = a.answer_id
and b.num = round(a.num);
An index on my_table (answer_id, num) will speed up the extra search.
This fails, leading to the default of "2":
LOWER(REPLACE(RQ.question, ' ', '_')) = 'overall_size'
That is because the question seems to be "average_overall_size", not "overall_size".
String parsing and manipulation is the pits in SQL; suggest using the application to handle such.
Also, be aware that you may need a separate subquery to compute aggregate (eg AVG()), else it might not be computed over the set of values you think.
Query into temp table, then join
First query should produce table as follows:
CREATE temp table, temp_average_size
widget_id
average_overall_size
rounded_average_size
115
1.80
2
LEFT JOIN
select s.*, a.word
from temp_average_size s LEFT JOIN answers a
ON (s.rounded_average_size = a.num AND a.answer_type = 'overall_size)

mysql usage of 'not in' without column value

i have a table Transactions that looks similar to this:
id Type Field ObjectId NewValue
1 AddLink HasMember 4567 someDomain/someDirectory/1231
2 AddLink HasMember 4567 someDomain/someDirectory/1232
3 AddLink HasMember 4567 someDomain/someDirectory/1233
4 DeleteLink HasMember 4567 someDomain/someDirectory/1231
The numeric end of "NewValue" is what i am interested in.
In Detail, i need those records where i have a record where type is "AddLink" and where no newer record of type "DeleteLink" exists, i.e. the records with id = 2 or 3 (since 4 deletes 1)
The "ObjectId" as well as the numeric bit of "NewValue" both are IDs of entries of the "tickets" table, and i need the relevant tickets.
i tried this:
SELECT `Tickets`.* FROM `Transactions` AS `addedLinks`
LEFT JOIN `Tickets` ON RIGHT (`addedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `addedLinks`.`Type` = 'AddLink'
AND `addedLinks`.`Field` = 'Hasmember'
AND `addedLinks`.`ObjectId` = '4567'
AND NOT RIGHT (`addedLinks`.`NewValue`, 4) in (
SELECT `Tickets`.* FROM `Transactions` AS `deletedLinks`
LEFT JOIN `Tickets` ON RIGHT (`deletedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `deletedLinks`.`Type` = 'DeleteLink'
AND `addedLinks`.`id` < `deletedLinks`.`id`
AND `deletedLinks`.`Field` = 'Hasmember'
AND `deletedLinks`.`ObjectId` = '4567' )
This gives me:
SQL Error (1241): Operand should contain 1 column(s)
Unless i got something wrong, the problem is
RIGHT (`addedLinks`.`NewValue`, 4)
in the "AND NOT ... in()" statement.
Could anyone point me in the right direction here?
[EDIT]
Thanks to David K-J, the following works:
SELECT `Tickets`.* FROM `Transactions` AS `addedLinks`
LEFT JOIN `Tickets` ON RIGHT (`addedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `addedLinks`.`Type` = 'AddLink'
AND `addedLinks`.`Field` = 'Hasmember'
AND `addedLinks`.`ObjectId` = '5376'
AND NOT (RIGHT (`addedLinks`.`NewValue`, 4)) in (
SELECT `id` FROM `Transactions` AS `deletedLinks`
WHERE `deletedLinks`.`Type` = 'DeleteLink'
AND `addedLinks`.`id` < `deletedLinks`.`id`
AND `deletedLinks`.`Field` = 'Hasmember'
AND `deletedLinks`.`ObjectId` = '5376' )
but i don't understand why?
The problem here is your sub-select, as you are using it to provide the value of an IN clause, your sub-select should only select the id field, i.e. Transactions.* -> Transactions.id
So you end up with:
...
AND NOT (RIGHT (`addedLinks`.`NewValue`, 4)) IN
SELECT id FROM Transactions AS deletedLinks WHERE
...
The reason for this is that IN requires a list to compare with, so foo IN ( 1,2,3,4,5 ). If your subquery is selecting multiple fields, the resulting list is conceptually a list of lists (AoAs) like, [1, 'a'], [2, 'b'], [3, 'c'] and it's going to complain at you =)
Ah that's so complicated and with subquery... make it simpler, will be much faster
CREATE TEMPORARY TABLE `__del_max`
SELECT `NewValue`, MAX(`id`) as id FROM tickets
WHERE type = 'DeleteLink'
GROUP BY NewValue;
CREATE INDEX _nv ON __del_max(`NewValue`)
SELECT * FROM `tickets`
LEFT OUTER JOIN `__del_max` ON tickets.NewValue = __del_max.NewValue AND __del_max.id > tickets.id
WHERE __del_max.id IS NULL
You can have it in single, big join, but it'd be beneficial to have it in TMP table so you can add an index ;)

mysql add key does not work

I have this query:
SELECT adressid, adressname FROM kino_adressen WHERE city ='Seattle'
I wanted to create an index like this
ALTER TABLE <tablename> ADD KEY index_abc(adressid, adressname(40))
But when I then check it by using:
EXPLAIN SELECT adressid, adressname FROM kino_adressen WHERE city ='Seattle'
It says
type = ALL
possible keys = NULL
key = NULL
...rows = 106
Can anyone give some piece of advice how to do this properly ?
// edit:
Another problem I do not understand:
SELECT DISTINCT
titel,
regie,
darsteller,
filmbild,
kino_filme.filmid,
kino_filme.beschreibung,
fsk,
filmlaenge,
verleih,
sprachfassung
FROM
kino_filme
LEFT JOIN kino_terminefilme ON (
kino_terminefilme.filmid = kino_filme.filmid
)
LEFT JOIN kino_termine ON (
kino_terminefilme.terminid = kino_termine.terminid
)
LEFT JOIN kino_kinos ON (
kino_kinos.kinoid = kino_termine.kinoid
)
LEFT JOIN kino_adressen ON (
kino_adressen.adressid = kino_kinos.adressid
)
WHERE
kino_adressen.adressid = 32038
And the result is like:
Why is kino_termine not using any index ?
I set it to PK while creating and even added an index afterwards, but none of those helped.
You added an index on the address but use the city in the where clause. Add an index on the city then it will be used.

sql query speed. Time response to long

I have problem with my mysl query. Response time is to long. My query:
SELECT SQL_CALC_FOUND_ROWS
t.id,
l.id_produkt_lista,
z.nr_zam,
k.nazwa_fv,
p.nazwa,
p.opis,
p.data_realizacji,
CONCAT(t.d_graf,'</br>', IF(t.D_d_graf IS NOT NULL,
DATE_FORMAT(t.D_d_graf, "%d-%m-%Y"),"")),
CONCAT(t.d_druk,'</br>', IF(t.D_d_druk IS NOT NULL,
DATE_FORMAT(t.D_d_druk, "%d-%m-%Y"),"")),
CONCAT(t.d_zgrz,'</br>', IF(t.D_d_zgrz IS NOT NULL,
DATE_FORMAT(t.D_d_zgrz, "%d-%m-%Y"),""))
FROM zamowienie_produkt_lista l
JOIN zamowienia_zamowienie z ON (l.id_zamowienie = z.id_zamowienie)
JOIN zamowienia_produkt p ON (l.id_produkt = p.id_produkt)
JOIN zamowienia_prac_tmp t ON (l.id_produkt = t.id_produkt)
JOIN zamowienia_klient k ON (z.id_klient = k.id_klient)
WHERE TRUE
AND id_typ_produkt = '1'
AND z.archiwum = 0
ORDER BY t.id
When I use it in phpmyadmin I have to wait about 10 second
Assuming that id_typ_produkt belongs to table zamowienie_produkt_lista, creating following indexes should help:
CREATE INDEX p_1_idx ON zamowienie_produkt_lista
(id_produkt, id_typ_produkt);
CREATE INDEX z_1_idx ON zamowienia_zamowienie
(id_zamowienie, archiwum);
You should also make sure that indexes on all *_id fields for all other joined tables exist.

Performance tuning

I have a performane problem. My manager said me to tune a select statement.
We are having a table
SELECT [AcctDetailReportId]
,[WorkOrderEneteredDate]
,[LocationName]
,[LocationNumber]
,[District]
,[CostCenter]
,[GLCode]
,[WorkType]
,[RequestType]
,[RequestCode]
,[ServiceLocation]
,[Cause]
,[Remedy]
,[RequestDescription]
,[CreatedBy]
,[Priority]
,[WorkOrderNumber]
,[Status]
,[DNE]
,[InvoiceNumber]
,[VendorCode]
,[VendorName]
,[Quote1]
,[Quote2]
,[Invoiceid]
,[InvoiceSubmittedDate]
,[WorkComplete]
,[TotalLaborCost]
,[TotalMaterialCost]
,[SalesTax]
,[InvoiceTotal]
,[WarrantyExpirationDate]
,[UnderWarranty]
,[MallName]
--,[AddressID]
--,[CommunicationID]
--,[ContactID]
--,[StateID]
--,[CountryID]
--,[LanguageID]
--,[AddressTypeID]
,[Line1]
,[Line2]
,[City]
,[Province]
,[Region]
,[ZipPostalCode]
--,[DeactivateDateTime]
--,[DeactivateUser]
,[CreateDateTime]
,[CreateUser]
--,[PreviousRecordID]
,[LocationState]
,[CheckNumber]
,[CheckDate]
FROM [Darden].[dbo].[RPT_AccountDetailReport]
GO"
which contains of 29000 records. it takes about 2 mins to retrieve data using Clustered Index Scan..
Table has only one Clustered Index.
Requirement is to get all records in a table and all columns.. But in reduced time..
Can any one help me on that...
Thanks,
Karthik
Have you reorganized/rebuilt your index(s) the script below will scripts to re/create all the indexes for a table where i.name = '%what ever you put here%'. There are a bunch of lines below that are remmed out that I have used in the past.
SELECT
--stats.object_id AS objectid,
--QUOTENAME(s.name) AS schemaname,
--stats.index_id AS indexid,
i.name AS index_name,
--stats.partition_number AS partitionnum,
stats.avg_fragmentation_in_percent AS frag,
stats.page_count,
QUOTENAME(o.name) AS objectname,
CASE
when stats.avg_fragmentation_in_percent < 30 then 'Reorganize'
when stats.avg_fragmentation_in_percent > 30 then 'Rebuild'
END AS 'action_to_take',
CASE
when stats.avg_fragmentation_in_percent < 30 then 'ALTER INDEX '+i.name+ ' ON ' +DB_NAME()+'.'+QUOTENAME(s.name)+'.'+QUOTENAME(o.name)+' REORGANIZE;'
when stats.avg_fragmentation_in_percent > 30 then 'ALTER INDEX '+i.name+ ' ON ' +DB_NAME()+'.'+QUOTENAME(s.name)+'.'+QUOTENAME(o.name)+' REBUILD;'
END AS 'Statement'
FROM
sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL , NULL, NULL) as stats,
sys.objects AS o,
sys.schemas AS s,
sys.indexes AS i
WHERE o.object_id = stats.object_id
AND s.schema_id = o.schema_id
AND i.object_id = stats.object_id
AND i.index_id = stats.index_id
AND i.name is not null and i.name not like '%missing index%'
AND stats.avg_fragmentation_in_percent >= 10.0
--AND stats.page_count >= 5000
--AND stats.index_id > 0
--and i.name like '%880%'
ORDER BY action_to_take,stats.avg_fragmentation_in_percent desc,stats.page_count desc
Or you can click on Display [estimated] Execution plan & SMS will generate any needed indexes.
HTH,
LarryR....